国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > 数据库 > 数据库应用 > MyBatis入门第2天--高级映射与查询缓存

MyBatis入门第2天--高级映射与查询缓存

来源:程序员人生   发布时间:2016-07-23 10:33:26 阅读次数:4102次
文档版本 开发工具 测试平台 工程名字 日期 作者 备注
V1.0 2016.06.28 lutianfei none

  • mybatis框架履行进程:

    • 1、配置mybatis的配置文件,SqlMapConfig.xml(名称不固定)
    • 2、通过配置文件,加载mybatis运行环境,创建SqlSessionFactory会话工厂
      • SqlSessionFactory在实际使用时按单例方式。
    • 3、通过SqlSessionFactory创建SqlSession
      • SqlSession是1个面向用户接口(提供操作数据库方法),实现对象是线程不安全的,建议sqlSession利用场合在方法体内。
    • 4、调用sqlSession的方法去操作数据。
      • 如果需要提交事务,需要履行SqlSession的commit()方法。
    • 5、释放资源,关闭SqlSession
  • mapper代理开发方法(建议使用)

    • 只需要程序员编写mapper接口(就是dao接口)
    • 程序员在编写mapper.xml(映照文件)和mapper.java需要遵守1个开发规范:
    • 1、mapper.xml中namespace就是mapper.java的类全路径。
    • 2、mapper.xml中statement的id和mapper.java中方法名1致。
    • 3、mapper.xml中statement的parameterType指定输入参数的类型和mapper.java的方法输入 参数类型1致。
    • 4、mapper.xml中statement的resultType指定输出结果的类型和mapper.java的方法返回值类型1致。
  • 本文内容:

    • 对定单商品数据模型进行分析。
    • 高级映照:(了解)
      • 实现1对1查询、1对多、多对多查询。
      • 延迟加载
    • 查询缓存
      • 1级缓存
      • 2级缓存(了解mybatis2级缓存使用处景)
    • mybatis和spirng整合(掌握)
    • 逆向工程(会用)

定单商品数据模型

数据模型分析思路

  • 1、每张表记录的数据内容
    • 分模块对每张表记录的内容进行熟习,相当于你学习系统需求(功能)的进程。
  • 2、每张表重要的字段设置
    • 非空字段、外键字段
  • 3、数据库级别表与表之间的关系
    • 外键关系
  • 4、表与表之间的业务关系
    • 在分析表与表之间的业务关系时1定要建立在某个业务意义基础上去分析
数据模型分析

  • 用户表user:
    • 记录了购买商品的用户信息
  • 定单表:orders
    • 记录了用户所创建的定单(购买商品的定单)
  • 定单明细表:orderdetail:
    • 记录了定单的详细信息即购买商品的信息
  • 商品表:items

    • 记录了商品信息
  • 表与表之间的业务关系:
    在分析表与表之间的业务关系时需要建立在某个业务意义基础上去分析。

  • 先分析数据级别之间有关系的表之间的业务关系:

  • usre和orders:

    • user—->orders : 1个用户可以创建多个定单,1对多
    • orders—>user : 1个定单只由1个用户创建,1对1
  • orders和orderdetail:

    • orders –> orderdetail:1个定单可以包括多个定单明细,由于1个定单可以购买多个商品,每一个商品的购买信息在orderdetail记录,1对多关系
    • orderdetail–> orders:1个定单明细只能包括在1个定单中,1对1
  • orderdetail和itesm:

    • orderdetail—> itesms:1个定单明细只对应1个商品信息,1对1
    • items–> orderdetail:1个商品可以包括在多个定单明细 ,1对多
  • 再分析数据库级别没有关系的表之间是不是有业务关系:

    • orders和items:
      • orders和items之间可以通过orderdetail表建立关系。
    • user 和 items : 通过其他表构成了多对多关系


1对1查询

  • 需求 : 查询定单信息,关联查询创建定单的用户信息
使用resultType方式查询
  • sql语句使用斟酌
  • 肯定查询的主表:定单表
  • 肯定查询的关联表:用户表
  • 关联查询使用内链接,还是外链接?
    • 由于orders表中有1个外键(user_id),通过外键关联查询用户表只能查询出1条记录,可使用内链接。
SELECT orders.*, USER.username, USER.sex, USER.address FROM orders, USER WHERE orders.user_id = user.id


  • 创建pojo(OrdersCustom.java)
    • 将上边sql查询的结果映照到pojo中,pojo中必须包括所有查询列名。
    • 原始的Orders.java不能映照全部字段,需要新创建的pojo。
    • 创建 1个pojo继承包括查询字段较多的po类。


  • OrdersMapperCustom.xml


  • OrdersMapperCustom.java

  • 编写测试类

    • 选择OrdersMapperCustom.java文件右键–>选择New–>Others–> Junit Test Case–>选择要测试的函数
    • 在OrdersMapperCustomTest.java中编写以下代码:
public class OrdersMapperCustomTest { private SqlSessionFactory sqlSessionFactory; // 此方法是在履行testFindUserById之前履行 @Before public void setUp() throws Exception { // 创建sqlSessionFactory // mybatis配置文件 String resource = "SqlMapConfig.xml"; // 得到配置文件流 InputStream inputStream = Resources.getResourceAsStream(resource); // 创建会话工厂,传入mybatis的配置文件信息 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void testFindOrdersUser() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); // 创建代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession .getMapper(OrdersMapperCustom.class); // 调用maper的方法 List<OrdersCustom> list = ordersMapperCustom.findOrdersUser(); System.out.println(list); sqlSession.close(); }


使用resultMap方式查询
  • sql语句 : 同resultType实现的sql

  • 使用resultMap映照的思路

    • 使用resultMap将查询结果中的定单信息映照到Orders对象中,在orders类中添加User属性,将关联查询出来的用户信息映照到orders对象中的user属性中。
  • Orders类中添加user属性

  • OrdersMapperCustom.xml

    • 定义resultMap
      • tyep : 表示将全部查询的结果映照到某个类中 eg:cn.itcast.mybatis.po.Orders
      • id:表示数据库表中查询列的唯1标识,定单信息的中的唯1标识,如果有多个列组成唯1标识,配置多个id
      • column:数据库表中定单信息的唯1标识列
      • property:定单信息的唯1标识列所映照到Orders中哪一个属性
      • association:用于映照关联查询单个对象的信息
      • property:要将关联查询的用户信息映照到Orders中哪一个属性
      • javaType:映照到user的哪一个属性
<!-- 定单查询关联用户的resultMap 将全部查询的结果映照到cn.itcast.mybatis.po.Orders中 --> <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap"> <!-- 配置映照的定单信息 --> <!-- id:指定查询列中的唯 1标识,定单信息的中的唯 1标识,如果有多个列组成唯1标识,配置多个id column:定单信息的唯 1标识 列 property:定单信息的唯 1标识 列所映照到Orders中哪一个属性 --> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property=note/> <!-- 配置映照的关联的用户信息 --> <!-- association:用于映照关联查询单个对象的信息 property:要将关联查询的用户信息映照到Orders中哪一个属性 --> <association property="user" javaType="cn.itcast.mybatis.po.User"> <!-- id:关联查询用户的唯1标识 column:指定唯 1标识用户信息的列 javaType:映照到user的哪一个属性 --> <id column="user_id" property="id"/> <result column="username" property="username"/> <result column="sex" property="sex"/> <result column="address" property="address"/> </association> </resultMap>


  • statement定义


  • OrdersMapperCustom.java

  • 测试代码

@Test public void testFindOrdersUserResultMap() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); // 创建代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession .getMapper(OrdersMapperCustom.class); // 调用maper的方法 List<Orders> list = ordersMapperCustom.findOrdersUserResultMap(); System.out.println(list); sqlSession.close(); }


resultType和resultMap实现1对1查询小结
  • resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,便可完成映照。
  • 如果没有查询结果的特殊要求建议使用resultType。

  • resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映照pojo的属性中。

  • resultMap可以实现延迟加载,resultType没法实现延迟加载。


1对多查询

  • 需求 : 查询定单及定单明细的信息。

  • sql语句

    • 肯定主查询表:定单表
    • 肯定关联查询表:定单明细表
    • 在1对1查询基础上添加定单明细表关联便可。
SELECT orders.*, USER.username, USER.sex, USER.address, orderdetail.id orderdetail_id, orderdetail.items_id, orderdetail.items_num, orderdetail.orders_id FROM orders, USER, orderdetail WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id


  • 分析 : 使用resultType将上边的 查询结果映照到pojo中,定单信息的就是重复。

  • 要求:对orders映照不能出现重复记录。

    • 在orders.java类中添加List<orderDetail> orderDetails属性。
    • 终究会将定单信息映照到orders中,定单所对应的定单明细映照到orders中的orderDetails属性中。
    • 映照成的orders记录数为两条(orders信息不重复)
    • 每一个orders中的orderDetails属性存储了该定单所对应的定单明细。

  • 在Orders.java中添加list定单明细属性

  • OrdersMapperCustom.xml


  • resultMap定义
    • 使用extends继承,不用在中配置定单信息和用户信息的映照
    • collection:对关联查询到多条记录映照到集合对象中
    • property:将关联查询到多条记录映照到cn.itcast.mybatis.po.Orders哪一个属性
    • ofType:指定映照到list集合属性中pojo的类型
<!-- 定单及定单明细的resultMap 使用extends继承,不用在中配置定单信息和用户信息的映照 --> <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersAndOrderDetailResultMap" extends="OrdersUserResultMap"> <!-- 定单信息 --> <!-- 用户信息 --> <!-- 使用extends继承,不用在中配置定单信息和用户信息的映照 --> <!-- 定单明细信息 1个定单关联查询出了多条明细,要使用collection进行映照 collection:对关联查询到多条记录映照到集合对象中 property:将关联查询到多条记录映照到cn.itcast.mybatis.po.Orders哪一个属性 ofType:指定映照到list集合属性中pojo的类型 --> <collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail"> <!-- id:定单明细唯 1标识 property:要将定单明细的唯1标识映照到cn.itcast.mybatis.po.Orderdetail的哪一个属性 --> <id column="orderdetail_id" property="id"/> <result column="items_id" property="itemsId"/> <result column="items_num" property="itemsNum"/> <result column="orders_id" property="ordersId"/> </collection> </resultMap>


  • OrdersMapperCustom.java

  • 测试代码:

@Test public void testFindOrdersAndOrderDetailResultMap() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); // 创建代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession .getMapper(OrdersMapperCustom.class); // 调用maper的方法 List<Orders> list = ordersMapperCustom .findOrdersAndOrderDetailResultMap(); System.out.println(list); sqlSession.close(); }


  • 小结
    • mybatis使用resultMap的collection对关联查询的多条记录映照到1个list集合属性中。
    • 使用resultType实现:
      • 将定单明细映照到orders中的orderdetails中,需要自己处理,使用两重循环遍历,去掉重复记录,将定单明细放在orderdetails中。


多对多查询

  • 需求 : 查询用户及用户购买商品信息。

  • sql语句

    • 查询主表是:用户表
    • 关联表:由于用户和商品没有直接关联,通过定单定单明细进行关联,所以关联表:ordersorderdetailitems
SELECT orders.*, USER.username, USER.sex, USER.address, orderdetail.id orderdetail_id, orderdetail.items_id, orderdetail.items_num, orderdetail.orders_id, items.name items_name, items.detail items_detail, items.price items_price FROM orders, USER, orderdetail, items WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id


  • 映照思路

    • 将用户信息映照到user中。
    • 在user类中添加定单列表属性List<Orders> orderslist,将用户创建的定单映照到orderslist
    • 在Orders中添加定单明细列表属性List<OrderDetail>orderdetials,将定单的明细映照到orderdetials
    • 在OrderDetail中添加Items属性,将定单明细所对应的商品映照到Items
  • OrdersMapperCustom.xml


  • resultMap定义
<!-- 查询用户及购买的商品 --> <resultMap type="cn.itcast.mybatis.po.User" id="UserAndItemsResultMap"> <!-- 用户信息 --> <id column="user_id" property="id"/> <result column="username" property="username"/> <result column="sex" property="sex"/> <result column="address" property="address"/> <!-- 定单信息 1个用户对应多个定单,使用collection映照--> <collection property="ordersList" ofType="cn.itcast.mybatis.po.Orders"> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <!-- 定单明细 1个定单包括 多个明细--> <collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail"> <id column="orderdetail_id" property="id"/> <result column="items_id" property="itemsId"/> <result column="items_num" property="itemsNum"/> <result column="orders_id" property="ordersId"/> <!-- 商品信息1个定单明细对应1个商品--> <association property="items" javaType="cn.itcast.mybatis.po.Items"> <id column="items_id" property="id"/> <result column="items_name" property="name"/> <result column="items_detail" property="detail"/> <result column="items_price" property="price"/> </association> </collection> </collection> </resultMap>
  • OrdersMapperCustom.java

  • 测试代码:

@Test public void testFindUserAndItemsResultMap() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); // 创建代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession .getMapper(OrdersMapperCustom.class); // 调用maper的方法 List<User> list = ordersMapperCustom.findUserAndItemsResultMap(); System.out.println(list); sqlSession.close(); }


  • 多对多查询总结
    • 将查询用户购买的商品信息明细清单,(用户名、用户地址、购买商品名称、购买商品时间、购买商品数量)
    • 针对上边的需求就使用resultType将查询到的记录映照到1个扩大的pojo中,很简单实现明细清单的功能。
  • 1对多是多对多的特例,以下需求:

    • 查询用户购买的商品信息,用户和商品的关系是多对多关系。
    • 需求1:
      • 查询字段:用户账号、用户名称、用户性别、商品名称、商品价格(最多见)
      • 企业开发中常见明细列表,用户购买商品明细列表,
      • 使用resultType将上边查询列映照到pojo输出。
    • 需求2:
      • 查询字段:用户账号、用户名称、购买商品数量、商品明细(鼠标移上显示明细)
      • 使用resultMap将用户购买的商品明细列表映照到user对象中。
  • 总结:

    • 使用resultMap是针对那些对查询结果映照有特殊要求的功能,比如特殊要求映照成list中包括多个list。

resultType与resultMap的总结

  • resultType:
  • 作用:
    • 将查询结果依照sql列名pojo属性名1致性映照到pojo中。
  • 场合:

    • 常见1些明细记录的展现,比如用户购买商品明细,将关联查询信息全部展现在页面时,此时可直接使用resultType将每条记录映照到pojo中,在前端页面遍历list(list中是pojo)便可。
  • resultMap:

    • 使用association和collection完成1对1和1对多高级映照(对结果有特殊的映照要求)。
  • association:

  • 作用:
    • 将关联查询信息映照到1个pojo对象中。
  • 场合:

    • 为了方便查询关联信息可使用association将关联定单信息映照为用户对象的pojo属性中,比如:查询定单及关联用户信息。
    • 使用resultType没法将查询结果映照到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap。
  • collection:

  • 作用:
    • 将关联查询信息映照到1个list集合中。
  • 场合:
    • 为了方便查询遍历关联信息可使用collection将关联信息映照到list集合中,比如:查询用户权限范围模块及模块下的菜单,可以使用collection将模块映照到模块list中,将菜单列表映照到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。
    • 如果使用resultType没法将查询结果映照到list集合中。


延迟加载

  • resultMap可以实现高级映照(使用association、collection实现1对1及1对多映照),association、collection具有延迟加载功能。

  • 需求:

    • 如果查询定单并且关联查询用户信息。如果先查询定单信息便可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
  • 延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能,由于查询单表要比关联查询多张表速度要快。

使用association实现延迟加载
  • 需求 : 查询定单并且关联查询用户信息

  • OrdresMapperCustom.xml

  • 需要定义两个mapper的方法对应的statement。

    • 1、只查询定单信息

      • SELECT * FROM orders
      • 在查询定单的statement中使用association去延迟加载(履行)下边的satatement(关联查询用户信息)

      • 2、关联查询用户信息

      • 通过上边查询到的定单信息中user_id去关联查询用户信息
      • 使用UserMapper.xml中的findUserById
  • 上边先去履行findOrdersUserLazyLoading,当需要去查询用户的时候再去履行findUserById,通过resultMap的定义将延迟加载履行配置起来。

  • 延迟加载resultMap

    • 使用association中的select指定延迟加载去履行的statement的id。
<!-- 延迟加载的resultMap --> <resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap"> <!--对定单信息进行映照配置 --> <id column="id" property="id"/> <result column="user_id" property="userId"/> <result column="number" property="number"/> <result column="createtime" property="createtime"/> <result column="note" property="note"/> <!-- 实现对用户信息进行延迟加载 select:指定延迟加载需要履行的statement的id(是根据user_id查询用户信息的statement) 要使用userMapper.xml中findUserById完成根据用户id(user_id)用户信息的查询,如果findUserById不在本mapper中需要前边加namespace column:定单信息中关联用户信息查询的列,是user_id 关联查询的sql理解为: SELECT orders.*, (SELECT username FROM USER WHERE orders.user_id = user.id)username, (SELECT sex FROM USER WHERE orders.user_id = user.id)sex FROM orders --> <association property="user" javaType="cn.itcast.mybatis.po.User" select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id"> <!-- 实现对用户信息进行延迟加载 --> </association> </resultMap>


  • OrderesMapperCustom.java

  • 测试思路:

    • 1、履行上边mapper方法(findOrdersUserLazyLoading),内部去调用cn.itcast.mybatis.mapper.OrdersMapperCustom中的findOrdersUserLazyLoading只查询orders信息(单表)。
    • 2、在程序中去遍历上1步骤查询出的List<Orders>,当我们调用Orders中的getUser方法时,开始进行延迟加载。
    • 3、延迟加载,去调用UserMapper.xml中findUserbyId这个方法获得用户信息。
延迟加载配置
  • mybatis默许没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。

  • 在mybatis核心配置文件中配置:

设置项 描写 允许值 默许值
lazyLoadingEnabled 全局性设置懒加载。如果设为‘false’,则所有相干联的都会被初始化加载。 true or false false
aggressiveLazyLoading 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每一个属性都按需加载。 true or false true
  • 在SqlMapConfig.xml中配置:

  • 测试代码

  • 延迟加载思考

    • 不使用mybatis提供的association及collection中的延迟加载功能,如何实现延迟加载?
  • 实现方法以下:

    • 定义两个mapper方法:
      • 1、查询定单列表
      • 2、根据用户id查询用户信息
    • 实现思路:
      • 先去查询第1个mapper方法,获得定单信息列表
      • 在程序中(service),按需去调用第2个mapper方法去查询用户信息。
  • 总之:使用延迟加载方法,先去查询简单的sql(最好单表,也能够关联查询),再去按需要加载关联查询的其它信息。




查询缓存

  • mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
  • mybaits提供1级缓存,和2级缓存。

  • 1级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有1个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是相互不影响的。

  • 2级缓存是mapper级别的缓存,多个SqlSession去操作同1个Mapper的sql语句,多个SqlSession可以共用2级缓存,2级缓存是跨SqlSession的。

  • 为何要用缓存?

    • 如果缓存中有数据就不用从数据库中获得,大大提高系统性能。


1级缓存

  • 1级缓存工作原理

  • 第1次发起查询用户id为1的用户信息,先去找缓存中是不是有id为1的用户信息,如果没有,从数据库查询用户信息。

  • 得到用户信息,将用户信息存储到1级缓存中。
  • 如果sqlSession去履行commit操作(履行插入、更新、删除),清空SqlSession中的1级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
  • 第2次发起查询用户id为1的用户信息,先去找缓存中是不是有id为1的用户信息,缓存中有,直接从缓存中获得用户信息。

1级缓存测试

  • mybatis默许支持1级缓存,不需要在配置文件去配置。
  • 依照上边1级缓存原理步骤去测试。
//OrdersMapperCusntomTest.java @Test public void testCache1() throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession();//创建代理对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //下边查询使用1个SqlSession //第1次发起要求,查询id为1的用户 User user1 = userMapper.findUserById(1); System.out.println(user1); // 如果sqlSession去履行commit操作(履行插入、更新、删除),清空SqlSession中的1级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。 //更新user1的信息 user1.setUsername("测试用户22"); userMapper.updateUser(user1); //履行commit操作去清空缓存 sqlSession.commit(); //第2次发起要求,查询id为1的用户 User user2 = userMapper.findUserById(1); System.out.println(user2); sqlSession.close(); }


  • 1级缓存利用
    • 正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
    • 1个service方法中包括 很多mapper方法调用。
service{ //开始履行时,开启事务,创建SqlSession对象 //第1次调用mapper的方法findUserById(1) //第2次调用mapper的方法findUserById(1),从1级缓存中取数据 //方法结束,sqlSession关闭 }
  • 如果是履行两次service调用查询相同 的用户信息,不走1级缓存,由于session方法结束,sqlSession就关闭,1级缓存就清空。


2级缓存

  • 原理

  • 首先开启mybatis的2级缓存。

  • sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到2级缓存中。

  • 如果SqlSession3去履行相同 mapper下sql,履行commit提交,清空该 mapper下的2级缓存区域的数据。

  • sqlSession2去查询用户id为1的用户信息,去缓存中找是不是存在数据,如果存在直接从缓存中取出数据。

  • 2级缓存与1级缓存区分,2级缓存的范围更大,多个sqlSession可以同享1个UserMapper的2级缓存区域。

  • UserMapper有1个2级缓存区域(按namespace分) ,其它mapper也有自己的2级缓存区域(按namespace分)。
  • 每个namespace的mapper都有1个2缓存区域,两个mapper的namespace如果相同,这两个mapper履行sql查询到数据将存在相同的2级缓存区域中。
开启2级缓存
  • mybaits的2级缓存是mapper范围级别,除在SqlMapConfig.xml设置2级缓存的总开关,还要在具体的mapper.xml中开启2级缓存。
  • 在核心配置文件SqlMapConfig.xml中加入
    • <setting name="cacheEnabled" value="true"/>
描写 允许值 默许值
cacheEnabled 对在此配置文件下的所有cache 进行全局性开/关设置。 true or false
  • 在UserMapper.xml中开启2级缓存,UserMapper.xml下的sql履行完成会存储到它的缓存区域(HashMap)。


  • 调用pojo类实现序列化接口

    • 为了将缓存数据取出履行反序列化操作,由于2级缓存数据存储介质多种多样,不1样在内存。
  • 2级缓存测试

@Test public void testCache2() throws Exception { SqlSession sqlSession1 = sqlSessionFactory.openSession(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); SqlSession sqlSession3 = sqlSessionFactory.openSession(); // 创建代理对象 UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); // 第1次发起要求,查询id为1的用户 User user1 = userMapper1.findUserById(1); System.out.println(user1); //这里履行关闭操作,将sqlsession中的数据写到2级缓存区域 sqlSession1.close(); //使用sqlSession3履行commit()操作 UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class); User user = userMapper3.findUserById(1); user.setUsername("张明明"); userMapper3.updateUser(user); //履行提交,清空UserMapper下边的2级缓存 sqlSession3.commit(); sqlSession3.close(); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); // 第2次发起要求,查询id为1的用户 User user2 = userMapper2.findUserById(1); System.out.println(user2); sqlSession2.close(); }


useCache配置
  • 在statement中设置useCache=false可以禁用当前select语句的2级缓存,即每次查询都会发出sql去查询,默许情况是true,即该sql使用2级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
  • 总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用2级缓存。
刷新缓存
  • 就是清空缓存
  • 在mapper的同1个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不履行刷新缓存会出现脏读。
  • 设置statement配置中的flushCache=”true” 属性,默许情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
  • 总结:1般下履行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以免数据库脏读。


mybatis整合ehcache
  • ehcache是1个散布式缓存框架。

  • 散布缓存

    • 我们系统为了提高系统并发,性能、1般对系统进行散布式部署(集群部署方式)
    • 不使用散布缓存,缓存的数据在各各服务单独存储,不方便系统 开发。所以要使用散布式缓存对缓存数据进行集中管理。
    • mybatis没法实现散布式缓存,需要和其它散布式缓存框架进行整合。


整合ehcache方法(掌握)
  • mybatis提供了1个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发便可。
  • mybatis和ehcache整合,mybatis和ehcache整合包中提供了1个cache接口的实现类。

  • mybatis默许实现cache类是:

  • 加入ehcache包

  • 整合ehcache

    • 配置mapper中cache中的type为ehcache对cache接口的实现类型。
  • 加入ehcache的配置文件(在classpath下配置ehcache.xml)

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"> <diskStore path="F:\develop\ehcache" /> <defaultCache maxElementsInMemory="1000" maxElementsOnDisk="10000000" eternal="false" overflowToDisk="false" timeToIdleSeconds="120" timeToLiveSeconds="120" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> </defaultCache> </ehcache>
  • 属性说明:
    • diskStore:指定数据在磁盘中的存储位置。
    • defaultCache:当借助CacheManager.add(“demoCache”)创建Cache时,EhCache便会采取<defalutCache/>指定的的管理策略
  • 以下属性是必须的:
    • maxElementsInMemory - 在内存中缓存的element的最大数目
    • maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
    • eternal - 设定缓存的elements是不是永久不过期。如果为true,则缓存的数据始终有效,如果为false那末还要根据timeToIdleSeconds,timeToLiveSeconds判断
    • overflowToDisk - 设定当内存缓存溢出的时候是不是将过期的element缓存到磁盘上
  • 以下属性是可选的:
    • timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默许值是0,也就是可闲置时间无穷大
    • timeToLiveSeconds - 缓存element的有效生命期,默许是0.,也就是element存活时间无穷大
      • diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默许是30MB.每一个Cache都应当有自己的1个缓冲区.
  • diskPersistent - 在VM重启的时候是不是启用磁盘保存EhCache中的数据,默许是false。
  • diskExpiryThreadIntervalSeconds - 磁盘缓存的清算线程运行间隔,默许是120秒。每一个120s,相应的线程会进行1次EhCache中数据的清算工作
  • memoryStoreEvictionPolicy - 当内存缓存到达最大,有新的element加入的时候, 移除缓存中element的策略。默许是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
2级利用场景
  • 对访问多的查询要求且用户对查询结果实时性要求不高,此时可采取mybatis2级缓存技术下降数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
  • 实现方法以下:通过设置刷新间隔时间,由mybatis每隔1段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
2级缓存局限性
  • mybatis2级缓存对细粒度的数据级别的缓存实现不好,比如以下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的2级缓存就没法实现当1个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,由于mybaits的2级缓存区域以mapper为单位划分,当1个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生