MyBatis高级

MyBatis高级

1.多参数传递问题

  • 多个参数封装成一个对象
    • 如果现有对象可以接收使用现有对象
    • 如果现有对象无法接收使用DTO(data transfer object)
  • 将多个参数封装成一个map(不推荐)
  • 在接口中给参数添加@param注解
    • List<Person> getPerson(@Param("name") String name, @Param("pwd") String pwd);

2.resultMap(核心)

思考:如果实体类的属性跟数据库的字段不一样,怎么处理

  • sql语句设置别名
  • 使用resultMap

2.1 解决属性名和字段名不一致的问题

将Person的pwd字段修改为password

<resultMap id="person_result" type="cn.blb.mybatis02.pojo.Person">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="pwd" property="password"/>
</resultMap>

<select id="getPerson" resultMap="person_result">
    select * from person where name = #{name} and pwd = #{pwd}
</select>

2.2 一对一

2.2.1 级联属性

  • dto

    @Data
    public class StudentDto {
        private int id;
        private String name;
        private String city;
        private Teacher teacher;
    }
    
  • mapper

    Student getStudentAndTeacher(int id);
    
    <resultMap id="studentMap" type="cn.blb.mybatis02.pojo.dto.StudentDto">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="city" column="city"/>
        <result property="teacher.id" column="tid"/>
        <result property="teacher.name" column="tname"/>
    </resultMap>
    
    <select id="getStudentAndTeacher" resultMap="studentMap">
        select s.*, t.id tid, t.name tname from student s, teacher t where s.tid = t.id and s.id = #{id}
    </select>
    

2.2.2 association

  • 实体类

    StudentDto getStudentAndTeacher(int id);
    
  • mapper

    <resultMap id="studentMap" type="cn.blb.mybatis02.pojo.dto.StudentDto">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="city" column="city"/>
        <association property="teacher" javaType="cn.blb.mybatis02.pojo.Teacher">
            <id property="id" column="tid" />
            <result property="name" column="tname"/>
        </association>
    </resultMap>
        
    <select id="getStudentAndTeacher" resultMap="studentMap">
        select s.*, t.id tid, t.name tname from student s, teacher t where s.tid = t.id and s.id = #{id}
    </select>
    

2.2.3 分步查询

  • mapper

    StudentDto getStudentAndTeacher(int id);
    
    <resultMap id="studentMap" type="cn.blb.mybatis02.pojo.dto.StudentDto">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="city" column="city"/>
        <association property="teacher" 
                     javaType="cn.blb.mybatis02.pojo.Teacher"	select="cn.blb.mybatis02.dao.TeacherMapper.getTeacherById" 
                     column="tid"
         />
    </resultMap>
    <select id="getStudentAndTeacher" resultMap="studentMap">
        select * from student where id = #{id}
    </select>
    
  • teacher

    • mapper

      Teacher getTeacherById(int id);
      
      <select id="getTeacherById" resultType="cn.blb.mybatis02.pojo.Teacher">
          select * from teacher where id = #{id}
      </select>
      

2.3 一对多

关键字:connection

  • 需求:一个老师对应多个学生
    • 根据老师的id去查询老师信息,并且查询出这个老师所带的所有学生

实现:

  • dto

    @Data
    public class TeacherDto {
        private int id;
        private String name;
        private List<Student> students;
    }
    
  • mapper

    TeacherDto getTeacherAndStudentById(int id);
    
    <resultMap id="teacherMap" type="cn.blb.mybatis02.pojo.dto.TeacherDto">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <!--
                ofType:返回值的对象的类型
                javaType:集合的类型,因为给我们封装好了,所以不用写全量名称
             -->
        <collection property="students" ofType="cn.blb.mybatis02.pojo.Student" javaType="list">
            <id property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="city" column="city"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
    
    <select id="getTeacherAndStudentById" resultMap="teacherMap">
        select t.*, s.id as sid, s.name as sname, s.city as city, s.tid as tid
        from teacher t,
        student s
        where t.id = s.tid
        and t.id = #{id}
    </select>
    

3.动态SQL(核心)

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦

为什么能够实现动态SQL: 基于 OGNL 的表达式,跟 JSTL 非常的相似

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

4.延迟加载

前置条件起码要查询两次
第一次查询的是学生的数据,第二次查询的是老师的数据,
但是在有的时候,只要学生的数据,有的时候需要学生+老师的数据,如果是第一种情况,第二次查询就没有必要去执行了
懒加载的核心说明:按需加载
需求表现的形式:有没有使用teacher这个对象

使用:两处
1.核心配置文件中添加一个配置

		<!-- 开启懒加载 ,默认值是false,true表示开启-->
        <setting name="lazyLoadingEnabled" value="true"/>

2.resultMap中添加一个属性
association fetchType=“lazy”

测试:不打印teacher的数据,观察sql语句
打印teacher的数据,观察sql语句

5.核心对象的生命周期

SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域,
用完之后需要赶紧关闭,否则资源被占用

  • SqlSessionFactoryBuilder:

    • 一旦创建了SqlSessionFactory,就不再需要它了
    • 局部变量、
  • SqlSessionFactory:

    • 说白了就可以想象为:数据库连接池
    • SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建一个实例
    • 因此SqlSessionFactory的最佳作用域是应用作用域(ApplocationContext)因此SqlSessionFactory的最佳作用域是应用作用域(ApplocationContext)
    • 最简单的就是使用单例模式或静态单例模式
  • SqlSession:

    • 连接到连接池的一个请求
    • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域
    • 用完之后需要赶紧关闭,否则资源被占用!

6.缓存

6.1 什么是缓存

  • 什么是缓存[Cache]?
    • 存在内存中的临时数据
    • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题
  • 为什么使用缓存?
    • 减少和数据库的交互次数,减少系统开销,提高系统效率
  • 什么样的数据可以使用缓存?
    • 经常查询并且不经常改变的数据 【可以使用缓存】

6.2 MyBatis缓存

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存,缓存可以极大的提高查询效率
  • MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
    • 默认情况下,只有一级缓存开启(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
    • 为了提高可扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存

6.2.1 一级缓存

  • 一级缓存也叫本地缓存:SqlSession

    • 与数据库同一次会话期间查询到的数据会放在本地缓存中
    • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库
        @Test
        public void test1() {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.getUserById(1);
            System.out.println(user);
    
            System.out.println("=====================================");
    
            User user2 =  mapper.getUserById(1);
            System.out.println(user2 == user);
        }
    
    

    缓存失效的情况:

    1. 查询不同的东西
    2. 增删改操作,可能会改变原来的数据,所以必定会刷新缓存
    3. 查询不同的Mapper.xml
    4. 手动清理缓存

6.2.2 二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
    工作机制

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    • 如果会话关闭了,这个会员对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的
    • 数据被保存到二级缓存中
      新的会话查询信息,就可以从二级缓存中获取内容
    • 不同的mapper查询出的数据会放在自己对应的缓存(map)中
      一级缓存开启(SqlSession级别的缓存,也称为本地缓存)
  • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存

  • 为了提高可扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值