mybatis的一级二级缓存原理及具体实现

本文详细解析MyBatis的一级缓存和二级缓存机制,包括概念、实现原理及应用场景,通过代码示例展示如何在实际项目中有效利用缓存提升查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一级缓存

概念

其实就是将查询出来的数据备份一份,再次需要该数据时,直接从备份数据中取出来,省去了再次查询数据库的时间。

创建数据库连接后,会使用到sqlsession对象,调用一个select语句后,返回的结果会存储到一个map中,再次调用该select时,会从map中获取到该数据,不会去从数据库查询。

当调用update、delete、insert时,缓存中的数据会被清除。

实现

同一个sqlsession两次select

public class UserMapperTest {
    public SqlSession sqlSession;
    public SqlSessionFactory sqlSessionFactory;
    public UserMapper userMapper;

    @Before
    public void setUp() throws Exception {
        String resource = "mybatis_config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        this.sqlSession = sqlSessionFactory.openSession(true);
        this.userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @Test
    public void testQueryUserByTableName() {
        User user = this.userMapper.queryUserByName("静静");
        System.out.println(user);
        User user2 = this.userMapper.queryUserByName("静静");
        System.out.println(user2);
    }
}

输出

2020-05-28 22:19:23,231 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==>  Preparing: select * from tb_user where name = ? 
2020-05-28 22:19:23,251 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:19:23,268 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <==      Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}

同一个sqlsession中update另一张表

		@Test
    public void testQueryUserByTableName() {
        User user = this.userMapper.queryUserByName("静静");
        System.out.println(user);
        //update另一张表
        Book book = new Book();
        book.setId(1);
        book.setPrice(BigDecimal.valueOf(2));
        BookMapper mapper = sqlSession.getMapper(BookMapper.class);
        mapper.updateByPrimaryKeySelective(book);
        User user2 = this.userMapper.queryUserByName("静静");
        System.out.println(user2);
    }

输出

2020-05-28 22:50:10,796 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==>  Preparing: select * from tb_user where name = ? 
2020-05-28 22:50:10,820 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:50:10,837 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <==      Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}
2020-05-28 22:50:10,861 [main] [dao.BookMapper.updateByPrimaryKeySelective]-[DEBUG] ==>  Preparing: update book SET price = ? where id = ? 
2020-05-28 22:50:10,861 [main] [dao.BookMapper.updateByPrimaryKeySelective]-[DEBUG] ==> Parameters: 2(BigDecimal), 1(Integer)
2020-05-28 22:50:10,868 [main] [dao.BookMapper.updateByPrimaryKeySelective]-[DEBUG] <==    Updates: 1
2020-05-28 22:50:10,868 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==>  Preparing: select * from tb_user where name = ? 
2020-05-28 22:50:10,869 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:50:10,873 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <==      Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}

调用clearCache效果是一样的

		@Test
    public void testQueryUserByTableName() {
        User user = this.userMapper.queryUserByName("静静");
        System.out.println(user);
        sqlSession.clearCache();
        User user2 = this.userMapper.queryUserByName("静静");
        System.out.println(user2);
    }

输出

2020-05-28 22:57:18,422 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==>  Preparing: select * from tb_user where name = ? 
2020-05-28 22:57:18,443 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:57:18,461 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <==      Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}
2020-05-28 22:57:18,463 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==>  Preparing: select * from tb_user where name = ? 
2020-05-28 22:57:18,463 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-05-28 22:57:18,466 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <==      Total: 1
User{id='1', userName='evan', password='123456', name='静静', age=16, sex=1, birthday='1990-09-01', created='2020-03-28 04:52:01', updated='2020-03-29 08:31:04'}

原理
  1. 在同一个sqlsession中,调用insert、update、delete其实都是调用了sqlSession.clearCache();
  2. 缓存存在了哪里(待更新)
应用场景
  1. 将sqlsession变为单例,在一些不经常更新内容的查询时,使用。

  2. 开启一个事物。

二级缓存

概念

作用范围是sqlSessionFactory,在一级缓存的基础上,不同的sqlSession调用同样的mapper中方法时,会从二级缓存中取出数据,当输出“Cache Hit Ratio”,说明是从二级缓存获取数据。前提是需要将bean对象序列化,因为二级缓存是将数据存储在磁盘上。

实现

在配置文件中打开缓存

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

在bean对应的xml中增加标签

<mapper namespace="dao.UserMapper">
    <cache/>
</mapper>

代码

		@Test
    public void testSecondCache() {
        this.userMapper.queryUserByName("静静");
        sqlSession.commit();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        UserMapper userMapperr2 = sqlSession2.getMapper(UserMapper.class);
        userMapperr2.queryUserByName("静静");
    }

		//序列化
		public class User implements Serializable{
      
    }

输出

2020-06-02 00:46:54,876 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==>  Preparing: select * from tb_user where name = ? 
2020-06-02 00:46:54,897 [main] [dao.UserMapper.queryUserByName]-[DEBUG] ==> Parameters: 静静(String)
2020-06-02 00:46:54,916 [main] [dao.UserMapper.queryUserByName]-[DEBUG] <==      Total: 1
2020-06-02 00:46:54,923 [main] [dao.UserMapper]-[DEBUG] Cache Hit Ratio [dao.UserMapper]: 0.5

注意

  • 必须调用sqlSession.commit()方法,二级缓存才会生效,否则第二次查询时,调用的是一级缓存。
应用场景

使用其他缓存

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值