当前位置:   article > 正文

Mybatis扩展

Mybatis扩展

 1. Myabtis注解开发

​    这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper映射文件了。我们先围绕一些基本的CRUD来学习,再学习复杂映射多表操作。

 1.1 常见注解

  @Insert:实现新增
  @Update:实现更新
  @Delete:实现删除
  @Select:实现查询
  @Result:实现结果集封装
  @Results:可以与@Result 一起使用,封装多个结果集
  @One:实现一对一结果集封装
  @Many:实现一对多结果集封装

​    使用注解开发 可以省略编写mapper的xml映射文件,直接在dao层的接口方法上面使用注解执行sql ,因为省略了映射文件,所以要把接口直接配置在核心配置文件的mapper标签中进行绑定

 1.2 核心配置文件

扫描使用注解的接口

  1. <mappers>
  2.     <!--扫描使用注解的接口-->
  3.     <mapper class="com.demo.mapper.IUserMapper"></mapper>
  4. </mappers>

或者指定扫描包含映射关系的接口所在的包也可以

  1. <mappers>
  2.     <!--扫描使用注解的接口所在的包-->
  3.     <package name="com.demo.mapper"></package>
  4. </mappers>

 2. 单表的操作

​    只需要在方法上加入对应操作的注解 参数中写要执行的sql即可

 查询全部用户 

  1. public interface IUserMapper {
  2.       @Select(" select * from user")
  3.       List<User> findAll();
  4.   }


 删除id为1的用户

  1. @Delete("delete from user where id = #{id}")
  2. int deleteUserById(int id);

 修改id为2的用户姓名

  1. @Update("update user set username = #{username} where id = #{id}")
  2. int updateUserById(@Param("username") String username, @Param("id") int id);

 添加一个用户

  1. @Insert("insert into user values(null,#{username},#{password},#{birthday})")
  2. int insertUser(User user);


 3. 多表的操作

 3.1 一对一查询

​    使用订单表和用户表 实现查询订单以及所属的用户信息

1. 创建实体类

2. 创建Mapper接口

  1. public interface IOrderMapper {
  2.       List<Orders> findAllOrders();
  3.   }

 方法上加入注解 

  1. public interface IUserMapper {
  2.       //根据ID查询用户
  3.       @Select("select * from user where id = #{id}")
  4.       User findUserById(int id);
  5.   }
  1. //查询全部订单
  2.       @Select("select * from orders")
  3.       @Results({ //id = true,代表是主键
  4.               @Result(id = true, property = "id", column = "id"),
  5.               @Result(property = "ordertime", column = "ordertime"),
  6.               @Result(property = "total", column = "total"),
  7.               @Result(property = "uid", column = "uid"),
  8.               @Result(property = "user", column = "uid",
  9.                       javaType = User.class,
  10.                       one = @One(select = "com.demo.mapper.IUserMapper.findUserById")
  11. //与用户接口中的方法关联
  12.               )
  13.           }
  14.       )
  15.       List<Orders> findAllOrder();

 测试结果

  在单元测试中 调用查询全部订单的方法 查看结果 查看执行的sql语句

  1. //查询全部订单信息 包含用户
  2.       @Test
  3.       public void findAllOrders(){
  4.           List<Orders> ordersList = mapper.findAllOrder();
  5.           //遍历结果
  6.           for (Orders orders : ordersList) {
  7.               System.out.println(orders);
  8.           }
  9.       }

 3.2 一对多查询

​    使用订单表和用户表 实现查询用户以及关联的订单列表

1. 创建实体类

2. 创建Mapper接口
 

  1. public interface UserMapper {
  2.             //查询全部用户 并且 查询出每个用户的订单
  3.       @Select("select * from user")
  4.       @Results({
  5.               @Result(id = true,property = "id",column = "id"),
  6.               @Result(property = "username",column = "username"),
  7.               @Result(property = "password",column = "password"),
  8.               @Result(property = "birthday",column = "birthday"),
  9.               @Result(property = "ordersList",column = "id",
  10.                       javaType = List.class,
  11.                       many = @Many(select = "com.zrrd.mapper.OrderMapper.findOrderByUid"))
  12.       })
  13.       List<User> findAllUser();
  14.   }
  1. //根据uid查询订单 订单接口中
  2.       @Select("select * from orders where uid = #{uid}")
  3.       List<Orders> findOrderByUid(int uid);


 注解方式实现多表查询
         使用@select注解 执行执行一次查询的sql
         使用@Results来进行结果映射 
         一对一:
                 javaType = 对象.class
                 one = @One(select = "指向一个新的查询方法的全路径")
         一对多:
                 javaType = List.class
                 many = @Many(select = "指向一个新的查询方法的全路径")

执行流程:

​        其实就是将Sql拆分 执行多次来完成结果映射 

​如查询全部员工 以及 所属部门

1. 先查询全部员工
2. 将查询到的每个员工的did 传入到指向的查询中进行查询

3.3 多对多查询

​    课堂案例

​    多对多的本质 就是双向的一对多查询

​    使用学生表和课程表 使用注解的方式 完成需求:

​    需求:

- 查询全部学生 以及学生学习的课程
- 查询全部课程 以及课程关联的学生

4. Mybatis的延迟加载策略

4.1 什么是延迟加载

​    通过前面的学习,我们已经掌握了 Mybatis 中一对一,一对多,多对多关系的配置及实现,可以实现对象的关联查询。实际开发过程中很多时候我们并不需要总是在加载用户信息时就一定要加载他的账户信息。此时就是我们所说的延迟加载。

​    延迟加载:就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

​    好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。【提高了数据库性能 单表操作】

​    坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。

 总结
         什么是延迟加载:在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)
         什么是立即加载:不管用不用,只要一调用方法,马上发起查询。
         使用场景: 在对应的三种表关系中:一对多,一对一,多对多
                            一对多,多对多:通常情况下我们都是采用延迟加载。
                            一对一:通常情况下我们都是采用立即加载。

4.2 实现延迟加载

 property:表示对象中的属性
 javaType:属性的类型
 column:指定按照那一列的值再去查询
 select:指定按照哪一个查询去查询 写法:接口的全类名 + 方法名。

4.2.1 全局实现

​    全局配置

  1.  <!--配置-->
  2.     <settings>
  3.         <!--开启懒加载-->
  4.         <setting name="lazyLoadingEnabled" value="true"/>
  5.         <!--关闭立即加载 按需加载-->
  6.         <setting name="aggressiveLazyLoading" value="false"/>
  7.     </settings>

 注意:
    ​    全局配置设置后 代表所有的加载 都设置为延迟加载
    ​    局部设置 优先级高于全局设置
    ​    在核心配置文件中要遵循mybatis的标签顺序 否则报错

4.2.2 局部实现

​    查询订单以及订单所属的用户

​    只要在接口方法中 加入一个设置延迟加载

fetchType = FetchType.LAZ 

  1. @Select("select * from user")
  2.     @Results({
  3.             @Result(id = true,property = "id",column = "id"),
  4.             @Result(property = "username",column = "username"),
  5.             @Result(property = "password",column = "password"),
  6.             @Result(property = "birthday",column = "birthday"),
  7.             @Result(property = "ordersList",column = "id",
  8.                     javaType = List.class,
  9.                     many = @Many(select = "com.zrrd.mapper.OrderMapper.findOrderByUid",fetchType = FetchType.LAZY))
  10.     })
  11.     List<User> findAllUser();

5. Mybatis中的缓存

5.1 什么是缓存

​    缓存这个概念其实就是在查询一次的时候 将结果存下来,下次直接可以获取,避免直接访问数据库,造成数据库压力过大。

5.2 为什么要使用缓存

​    像大多数的持久化框架一样,Mybatis 也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能。

​    Mybatis 中缓存分为一级缓存,二级缓存。

​    缓存的使用场景

1. 适用缓存
     经常使用
     不经常发生改变
     数据的正确与否对最终结果影响不大的
     如 省份信息 部门信息 专业信息
2. 不适用缓存
     经常改变的是数据
     数据的正确与否对最终结果影响很大的
     例如:商品的库存,银行的汇率,股市的牌价

5.3 一级缓存

​    一级缓存 也叫本地缓存,它指的是Mybatis中SqlSession对象的缓存,一级缓存是一直开启的; 

​    与数据库同一次会话期间查询到的数据会放在本地缓存中。以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库;

​    当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有,有的话直接拿出来用。

​    当SqlSession对象消失时,mybatis的一级缓存也就消失了。

​    一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。

一级缓存失效情况

1. sqlSession不同。
2. sqlSession相同,查询条件不同.(当前一级缓存中还没有这个数据)
3. sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
4. sqlSession相同,手动清除了一级缓存(缓存清空)  openSession.clearCache();

5.4 二级缓存

     二级缓存也叫全局缓存 基于namespace级别的缓存:一个namespace对应一个二级缓存。

​    工作机制:

1. 一个会话(SqlSession),查询一条数据,这个数据就会被放在当前会话的一级缓存中;
2. 如果会话关闭(close);一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容;
3. 不同namespace查出的数据会放在自己对应的缓存中(map)

​         使用步骤:

1. 让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
2. 让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
3. 让当前的操作支持二级缓存(在select标签中配置)默认就是支持的
4. 让封装数据的实体类实现Serializable接口

  1. <settings>
  2. <!-- 开启二级缓存的支持 -->
  3. <setting name="cacheEnabled" value="true"/>
  4. </settings>
  1. @CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
  2. public interface IUserDao {}

​    因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存

二级缓存的注意事项:
  ​    当我们在使用二级缓存时,所缓存的类一定要实现 java.io.Serializable 接口,这样就可以使用序列化方式来保存对象。

注解方式实现:

maybatis基于注解的二级缓存的步骤

1. 在 SqlMapConfig 中开启二级缓存支持
2. 在持久层接口中使用注解配置二级缓存
3. 实体类实现implements Serializable接口

5.5 一级缓存和二级缓存的区别

  一级缓存:也称为本地缓存,是MyBatis中SqlSession对象的一部分,生命周期与SqlSession相同。一级缓存是默认开启的,无法关闭。
  二级缓存:是Mapper级别的缓存,同一个namespace共享,生命周期与SqlSessionFactory相同,因此跨多个SqlSession。二级缓存需要手动开启和配置。
  一级缓存不能跨SqlSession使用,而二级缓存可以。
  一级缓存不可以关闭,二级缓存可以手动关闭(默认也是开启的)


  其实Mybatis中的缓存 我们基本上不用 因为我们之后会学习更好的框架来做缓存 Redis

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/540888
推荐阅读
相关标签
  

闽ICP备14008679号