在mybatis中,只有resultMap才具有延迟加载的功能。
1.在订单查询中实现对用户信息的延迟加载。
使用association中的select去指定延迟加载需要执行的statement的id。
<!-- 延迟加载的resultMap --> <resultMap id="ordersUserLazyLoading" type="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"/> <!-- 实现对用户信息进行延迟加载 select:指定延迟加载需要执行的statement的id(根据statement的id查询到的sql语句) 要使用userMapper.xml中完成根据用户id(user_id)用户信息的查询 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="com.beyond.mybatis.po.User" select="com.beyond.mybatis.mapper.UserMapper.selectUser" column="user_id"> </association> </resultMap> <!-- 查询订单关联查询用户信息,延迟加载用户信息 --> <select id="findOrdersUserLazyLoading" resultMap="ordersUserLazyLoading"> select * from orders </select>
编写接口方法:
//查询订单关联查询用户,用户信息延迟加载 List<Orders> findOrdersUserLazyLoading() throws Exception;
编写测试方法:
测试思路:
1、执行上边mapper方法,内部只查询了orders表
2、在程序中遍历上一步骤查询出的List<Orders>,当我们调用Orders中的getUser方法时,开始进行延迟加载。
3、延迟加载,去掉用UserMapper.xml中的selectUser这个方法获取用户信息。
首先:需要在sqlMapConfig.xml中开启延迟加载的开关。
<!-- 全局参数配置 --> <settings> <!-- 打开延迟加载的开关 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 将积极加载改为消极加载 --> <setting name="aggressiveLazyLoading" value="false"/> </settings>
@Test //查询订单关联查询用户,用户信息延迟加载 public void testfindOrdersUserLazyLoading() throws Exception{ SqlSession sqlSession = factory.openSession(); //通过反射拿到UserMapper的代理对象 OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class); List<Orders> list = ordersMapperCustom.findOrdersUserLazyLoading(); //遍历上边的订单列表 for (Orders orders: list) { User user = orders.getUser(); System.out.println(user); } }
collection的用户可以参考association。
缓存:
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybatis提供一级缓存和二级缓存。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造SqlSession对象,在对象中有一个数据结构(HashMap)
用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互不影响的。
二级缓存是mapper级别的缓存,多个sqlsession去操作同一个Mapper的sql语句,多个sqlsession可以共用二级缓存,
二级缓存是跨SqlSession的。
为什么要用缓存?
如果缓存中有数据就不用从数据库中获取,大大提高系统性能。
一级缓存
下面是根据id查询用户的一级缓存:
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户
信息。得到用户信息,将用户信息存储到一级缓存中。
如果sqlsession去执行commit操作(插入、更新、删除),清空sqlsession中的一级缓存,这样做的目的是为了
让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id位1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
mybatis默认开启了一级缓存。
//一级缓存测试 public void testCache1() throws Exception{ SqlSession sqlSession = factory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //两个都是使用的同一个sqlsession //第一次发起请求,查询id为1的用户,从数据看查 User user1 = userMapper.selectUser(1); System.out.println(user1); //第二次发起请求,查询id为1的用户,从缓存中取 User user2 = userMapper.selectUser(1); System.out.println(user2); }
二级缓存:
首先开启mybatis的二级缓存
sqlsession1取查询用户id为1的用户信息,查询到用户信息会将查询数据存储到二级缓存中。
sqlsession2去查询用户id为1的用户信息,去缓存中找是否存在数据,如果存在直接从缓存中取出数据。
sqlsession3去执行相同mapper下sql,执行commit提交,清空该mapper下的二级缓存区域的数据。
二级缓存与一级缓存区别:二级缓存的范围更大,多个sqlsession可以共享一个userMapper的二级缓存区域。
userMapper有一个二级缓存区域(按namespace分),其他mapper也有自己的二级缓存区域(按namespace分)
每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql
查询到数据将存在相同的二级缓存区域中。
开启二级缓存:
在sqlMapConfig.xml中的settings中加入(默认开启的)
<!-- 开启二级缓存 --> <setting name="cacheEnable" value="true"/>
在userMapper.xml中开启二级缓存,userMapper下的sql语句执行完会存储到它的二级缓存中
<mapper namespace="com.beyond.mybatis.mapper.UserMapper"> <!-- 开启本mapper的namespace下的二级缓存 --> <cache/>
调用的pojo类实现序列化接口
为了将缓存数据取出,执行反序列化操作,因为二级缓存的存储介质是多样的,不一定在内存
//二级缓存测试 public void testCache2() throws Exception{ SqlSession sqlSession1 = factory.openSession(); SqlSession sqlSession2 = factory.openSession(); SqlSession sqlSession3 = factory.openSession(); UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class); UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class); UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class); //两个都是使用的同一个sqlsession //第一次发起请求,查询id为1的用户,从数据看查 User user1 = userMapper1.selectUser(1); System.out.println(user1); //这里执行关闭操作,将sqlsession中的数据写到二级缓存中 sqlSession1.close(); //使用sqlSession3执行commit操作 User user3 = userMapper3.selectUser(1); user3.setUsername("king"); userMapper3.updateUser(user3); //执行提交,清空UserMapper下边的二级缓存 sqlSession3.commit(); sqlSession3.close(); //第二次发起请求,查询id为1的用户,从缓存中取 User user2 = userMapper2.selectUser(1); System.out.println(user2); sqlSession2.close(); }
禁用二级缓存
<select id="selectUser" parameterType="int" resultType="user" useCache="false">
对于数据变化比较快的,且每次都要获取最新的可以禁用二级缓存。
刷新缓存:(默认为true)
<update id="updateUser" parameterType="com.beyond.mybatis.po.User" flushCache="true">
使用自定义的缓存。
1.实现cache接口(org.apache.ibatis.cache.Cache)
2.在cache标签中引用。
mybatis整合ehcache
在pom加入ehcache整合mybatis的依赖jar包
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.1.0</version> </dependency>
在UserMapper.xml中引入这个class
<!-- 开启本mapper的namespace下的二级缓存 --> <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>