首页 > 代码库 > Mybatis学习(6)动态加载、一二级缓存

Mybatis学习(6)动态加载、一二级缓存

一、动态加载:

resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。

需求:

如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。

需要先说明下是按照这个sql的思路来实现延迟加载的:

mysql> select orders.*, (select user.username from user where orders.user_id = user.id) username from orders;
技术分享
(对于这种查询,可以分成两部来理解,首先忽略整个select子查询,查出订单表中的数据,然后根据订单表的user_id执行子查询,对于一个orders的user_id,子查询只能返回一条数据,如果子查询返回多条数据则会出错,另外,每一条select子查询只能查询一个字段。)
 
mapper.xml:
<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();
    }
View Code

可以看到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)动态加载、一二级缓存