2022-09-19 张宁杰 第六小组 mybatis(2)

如果我们导入依赖出现错误如何处理?

  • 到我们的仓库中删除下载好的jar包,然后重新下载

resultType:

  • 结果集的自动映射,必须写,对象属性名和查询结果的列名必须对应上

parameterType:

  • 参数类型,可以自动解析,可以写不写,如果是我们自定义的引用数据类型,建议写上全类名

@Param的含义

List<User> selectUserByIds(@Param("ids") List<Integer> ids);

使用注解来给参数命名@Param("命名")

dao层方法传入参数的两种策略

1、传入User对象,传入一个参数。
   场景:User类中的属性非常多,id,username,password,realname,profile,gender.....
   User user = new User(null,"admin","123456",null,null,null,null
2、传入username,password两个参数,规范要求,如果需要传入多个参数,参数个数不要超过3个
  • 当我们的mapper接口传入多个参数的时候,尽量保证类型的统一。
  • 参数的类型要么是java内置的数据类型,包装器类型或者是String,要么是集合
  • 正例:
    Integer ,String
    String String
    String List
  • 反例:
    User Student
    User List
    Integer Student
  1. 如果传入的是User对象,在mapper.xml映射文件中,就必须和对象的属性名匹配
  2. 如果传入的是java内置的数据类型的参数,String,Integer..,如果只传一个参数,直接使用#{参数名},#{param1},#
  3. 如果传入的是java内置的数据类型的参数,String,Integer..,如果传入多个参数,必须使用#{paramN}.#{arg0},不能用#
  • 原理(mybatis传入参数的策略,封装成了一个map集合):
Mybatis在封装参数的时候,封装成了一个Map集合,
如果传入的是User对象,value:{“username”:"admin","password":"123456","id":"1"}
【"username":"admin"】,【"password":"123456"】
如果传入的是一个内置类型的参数,字面量  【"xxxx":"admin"】
如果从传入的是多个参数,【"param1":"admin"】,【"param2":"123456"】,底层封装的map集合,arg0和arg1。起了个默认的别名叫param1,param2
如果传入的是集合,【"param1":"{1,2,3,4,5}"】
dao层中的方法:
User selectUserByUsernameAndPassword(@Param("username") String username,@Param("password") String password);
  • 结论:如果需要传入多个参数,我们希望在mapper.xml中和传入对象一样使用参数的名直接赋值,#{username},使用@Param注解起名,最好还是通过传入对象来解决问题!!!!

测试类规范

  • 测试类的类名,以目标类开头,以Test结尾
  • 测试类中的测试方法,尽量以目标方法的方法名结尾,test目标方法名

mybatis配置文件部分标签

  • typeAliases标签

  • <!--  别名:各类起别名,给实体类起别名  -->
        <!-- 注意事项:typeAliases必须放在environments上面 -->
        <typeAliases>
            <!--  <typeAlias type="com.jsoft.entity.User" alias="user"></typeAlias>-->
            <!--  当前包下的所有的实体类都是以类名的首字母小写来设置别名 -->
            <!-- 场景:当前包下的某个类不想以类名小写来当做别名  -->
            <package name="com.jsoft.entity"/>
        </typeAliases>
    
  • dataSource标签,从外部文件读取相应的配置

  • <!-- 引入外部的资源文件 -->
    <properties resource="db.properties"></properties>
    <dataSource type="com.jsoft.datasource.DruidDataSourceFactory">
                    <!-- property标签中的name属性只需要按照druid的命名规则命名即可  -->
                    <property name="druid.driverName" value="${druid.driverName}"/>
                    <property name="druid.url" value="${druid.url}"/>
                    <property name="druid.username" value="${druid.username}"/>
                    <property name="druid.password" value="${druid.password}"/>
    </dataSource>
    <!--资源文件-->
    package com.jsoft.datasource;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.apache.ibatis.datasource.DataSourceFactory;
    
    import javax.sql.DataSource;
    import java.util.Properties;
    
    public class DruidDataSourceFactory implements DataSourceFactory {
    
        private Properties properties;
    
        @Override
        public void setProperties(Properties properties) {
            // 直接把mybatis-config中的参数封装成properties
            this.properties = properties;
        }
    
        @Override
        public DataSource getDataSource() {
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.configFromPropety(properties);
            return druidDataSource;
        }
    }
    
    
  • settings标签,mybatis的其他配置文件,此标签要放在properties下

  • <settings>
            <!-- 数据库的字段名以下划线命名的自动转换成小驼峰 -->
            <setting name="mapUnderscoreToCamelCase" value="true"/>
            <!-- 日志实现:记录发生过的事情,主要是记录在本地,后期运营维护,配置文件log4j.properties中 -->
            <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    

数据库表(实体类)关系

  • 一对一、一对多

多表查询的问题

  • 使用SQL99语法

  • sql语句应该使用左连接还是内连接?

    • 无论主表中的数据是否和从表有关联关系,主表中的数据都需要显示出来(主从关系),此时不使用内连接
    • 只要有关联的数据,必须用inner join
    • 如果两张表中的数据都是有关联的(并列关系),推荐使用inner join,效率高于left join
  • resultMap:自定义结果集映射

  • 一对一

    • 第一种方式
  • <resultMap id="employeeResult" type="employee">
            <id property="id" column="eid"></id>
            <result property="name" column="ename"></result>
        //dept的封装策略
            <association property="dept" javaType="dept">
                <id property="id" column="did"></id>
                <result property="name" column="dname"></result>
            </association>
     </resultMap>
    <select id="findEmployeeById" resultMap="employeeResult">
            select e.id eid,e.name ename,d.id did,d.name dname
            from employee e
            inner join dept d
            on e.did = d.id
            where e.id = #{id}
    </select>
    
    • 第二种方式(分页查询)
  • id->员工->did->部门

  • <resultMap id="employeeResult" type="employee">
            <!--如果列名和类中的属性名相同,id,result可以省略的-->
            <!-- 分步查询,dept的封装策略,前提条件,在对应的对象的mapper接口中,恰好有要查询的数据 -->
            <association property="dept" javaType="dept" 								       select="com.jsoft.dao.DeptMapper.findDeptById" column="did"></association>
    </resultMap>
    <select id="findEmployeeById" resultMap="employeeResult">
            select id,name,did from employee where id = #{id}
        </select>
    <!--这种写法不规范,因为在DeptMapper中可能有一个根据部门号查询数据的方法,最好不要这样书写-->
        <select id="findDeptById" resultType="dept">
            select id,name from dept where id = #{id}
        </select>
    <!--这块代码应该存在于DeptMapper中-->
    

    一对多

    • did->部门->did->员工

    • <!--在EmployeeMapper.xml中-->
      <select id="getEmpByDid" resultType="com.jsoft.entity.Employee">
              select id,name,did from employee where did = #{did}
      </select>
      <!--在DeptMapper.xml中-->
      <resultMap id="deptEmpResult" type="dept">
              <id property="id" column="did"></id>
              <result property="name" column="dname"></result>
              <collection property="employees" ofType="employee" select="com.jsoft.dao.EmployeeMapper.getEmpByDid" column="id">
          	</collection>
       </resultMap>
       <select id="findAllDepts" resultMap="deptEmpResult">
              select
                  id,name
              from
                  dept
        </select>
      

一级缓存:sqlSession级别的缓存

  • 执行流程:第一次发起查询sql查询用户id为3的用户,先去缓存中查看是否有id为3的用户,如果没有,再去数据库中查询,
  • 如果查到了,则把这条记录放进缓存中。
  • 如果session执行了插入,更新,删除操作,以及缓存会被清空
  • mybatis是默认开启一级缓存
  • 一级缓存失效的情况:
    * 1、sqlSession不同
    * 2、当sqlSession对象相同,查询的数据不同。
    * 3、当sqlSession对象相同,两次查询之间进行插入,修改,删除的操作
    * 4、当sqlSession对象相同,两次查询之间手动清除了一级缓存

二级缓存:mapper级别的缓存,接口级别的。

  • 多个sqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,所得到的数据会存在二级缓存中
  • 二级缓存是跨sqlSession的
  • 二级缓存相比一级缓存范围更大。多个sqlSession可以共享一个二级缓存
  • 当session关闭时,会把数据提交到二级缓存
  • 查询时,从二级缓存中获取到的是数据的镜像,并不是真实的数据
  • <!-- 开启二级缓存 -->
        <!--
            eviction:缓存满了的淘汰机制
                1.LRU:最近最少使用的,最长时间不适用的
                2.FIFO:先进先出
                3.SOFT:软引用,基于垃圾回收器状态的软引用规则
                4.WEAK:弱引用,基于垃圾回收机状态的弱引用规则
           flushInterval:刷新时间间隔,单位毫秒
           size:缓存最多可以存多少个对象,一般情况下1024个,不宜设置过大
           redOnly:只读,默认是false,不允许修改缓存
        -->
        <cache eviction="LRU" flushInterval="10000" ></cache>
    

延迟加载(懒加载):什么时候用,什么时候再去加载,不用的时候,不加载。

posted @ 2022-09-21 09:33  贵妃就是贵妃  阅读(19)  评论(0编辑  收藏  举报