首页 > 代码库 > Mybatis学习(6)动态加载、一二级缓存
Mybatis学习(6)动态加载、一二级缓存
一、动态加载:
resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
需求:
如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
需要先说明下是按照这个sql的思路来实现延迟加载的:
<mapper namespace="com.cy.mapper.OrdersMapperCustom"> <!-- 延迟加载的resultMap --> <resultMap type="com.cy.po.Orders" id="OrdersLazyLoadingUser"> <id column="id" property="id"></id> <result column="user_id" property="userId"></result> <result column="number" property="number"></result> <result column="createtime" property="createtime"></result> <result column="note" property="note"></result> <!-- 实现对用户信息进行延迟加载 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="com.cy.po.User" column="user_id" select="com.cy.mapper.UserMapper.findUserById"> </association> </resultMap> <!-- 查询订单关联查询用户,用户信息需要延迟加载 --> <select id="findOrdersLazyLoadingUser" resultMap="OrdersLazyLoadingUser"> select * from orders; </select> </mapper>
这边需要配置settings 延迟加载:
<settings> <!-- 打开延迟加载 的开关 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 将积极加载改为消极加载即按需要加载 --> <setting name="aggressiveLazyLoading" value="false"/
</settings>
mapper接口:
//查询订单关联查询用户,用户信息是延迟加载 public List<Orders> findOrdersLazyLoadingUser() throws Exception;
测试代码:
// 查询订单关联查询用户,用户信息使用延迟加载 @Test public void FindOrdersLazyLoadingUser() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); OrdersMapperCustom ordersMapperCustom = sqlSession.getMapper(OrdersMapperCustom.class); // 查询订单信息(单表) List<Orders> orders = ordersMapperCustom.findOrdersLazyLoadingUser(); for(Orders order: orders){ // 执行getUser()去查询用户信息,这里实现按需加载 User user = order.getUser(); System.out.println(user); } sqlSession.close(); }
可以看到console输出的打印语句:
DEBUG [main] - Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@20e6423f]
DEBUG [main] - ==> Preparing: select * from orders;
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 3
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id=?
DEBUG [main] - ==> Parameters: 1(Integer)
DEBUG [main] - <== Total: 1
------->> User [id=1, username=王五, sex=2, birthday=null, address=null]
------->> User [id=1, username=王五, sex=2, birthday=null, address=null]
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE id=?
DEBUG [main] - ==> Parameters: 10(Integer)
DEBUG [main] - <== Total: 1
------->> User [id=10, username=张三, sex=1, birthday=Thu Jul 10 00:00:00 CST 2014, address=北京市]
DEBUG [main] - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@20e6423f]
二、1级缓存、2级缓存:
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
1.一级缓存:
工作原理:
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
测试代码:
一级缓存不需要在配置文件中配置,mybatis默认支持一级缓存;
1 // 一级缓存测试 2 @Test 3 public void testCache1() throws Exception { 4 SqlSession sqlSession = sqlSessionFactory.openSession(); 5 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 6 // 第一次发起请求,查询id为1的用户 7 User user1 = userMapper.findUserById(1); 8 System.out.println(user1); 9 10 // 如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。 11 // 更新user1的信息 12 // user1.setUsername("测试用户22"); 13 // userMapper.updateUser(user1); 14 // //执行commit操作去清空缓存 15 // sqlSession.commit(); 16 17 // 第二次发起请求,查询id为1的用户 18 User user2 = userMapper.findUserById(1); 19 System.out.println(user2); 20 21 sqlSession.close(); 22 }
Mybatis学习(6)动态加载、一二级缓存