MyBatis缓存学习(二)

在上一篇中,梳理了MyBatis一级缓存命中原则。跟踪代码,了解了具体的业务实现逻辑,这一篇,简单的记录MyBatis一级缓存的生命周期和与Spring整合后,事务管理MyBatis中的一级缓存。部分代码与图片可以查看MyBatis缓存学习(一)。

MyBatis一级缓存命中原则

一 MyBatis一级缓存生命周期

1.1 执行SqlSession的commit()、close()、rollback()方法

示例代码:

@Test
public void commitTest() throws IOException {
        SqlSession sqlSession = this.getSqlSession();
        UserInfo userInfo1 = sqlSession.selectOne("org.yoko.com.dao.UserInfoDao.queryById1", 1);
        logger.info("方法执行前,查询结果:" + userInfo1);

        sqlSession.commit();
//        sqlSession.close();
//        sqlSession.rollback();

        UserInfo userInfo2 = sqlSession.selectOne("org.yoko.com.dao.UserInfoDao.queryById1", 1);
        logger.info("方法执行后,查询结果:" + userInfo2);
        logger.info("方法执行前后,查询结果是否相同:" + (userInfo1 == userInfo2));
}

控制台日志打印:

2020-09-27 10:43:39,310 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==>  Preparing: select id, name, age from user_info where id = ? 
2020-09-27 10:43:39,354 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==> Parameters: 1(Integer)
2020-09-27 10:43:39,416 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - <==      Total: 1
2020-09-27 10:43:39,417 INFO [CacheDateTest] - 方法执行前,查询结果:UserInfo(id=1, name=赵一, age=21)
2020-09-27 10:43:39,417 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==>  Preparing: select id, name, age from user_info where id = ? 
2020-09-27 10:43:39,417 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==> Parameters: 1(Integer)
2020-09-27 10:43:39,418 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - <==      Total: 1
2020-09-27 10:43:39,418 INFO [CacheDateTest] - 方法执行后,查询结果:UserInfo(id=1, name=赵一, age=21)
2020-09-27 10:43:39,418 INFO [CacheDateTest] - 方法执行前后,查询结果是否相同:false

在执行这三个方法后,一级缓存会被清空。跟踪代码发现,commit()方法最后会执行PerpetualCache类的clear()方法,即HashMap的clear()方法;rollback()方法最后也会执行PerpetualCache类的clear()方法;close()方法在BaseExecutor类中会调用rollback()方法,并且会把缓存置为null。

1.2 SQLSession执行insert()、update()和delete()方法,与操作表无关

示例代码

@Test
public void dmlTest() throws IOException {
        SqlSession sqlSession = this.getSqlSession();
        UserInfo userInfo1 = sqlSession.selectOne("org.yoko.com.dao.UserInfoDao.queryById1", 1);
        logger.info("方法执行前,查询结果:" + userInfo1);

        sqlSession.insert("org.yoko.com.dao.UserInfoDao.queryById1", 1);
//        sqlSession.update("org.yoko.com.dao.UserInfoDao.queryById1", 1);
//        sqlSession.delete("org.yoko.com.dao.UserInfoDao.queryById1", 1);

        UserInfo userInfo2 = sqlSession.selectOne("org.yoko.com.dao.UserInfoDao.queryById1", 1);
        logger.info("方法执行后,查询结果:" + userInfo2);
        logger.info("方法执行前后,查询结果是否相同:" + (userInfo1 == userInfo2));
}

控制台日志打印

2020-09-27 13:42:56,027 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==>  Preparing: select id, name, age from user_info where id = ? 
2020-09-27 13:42:56,072 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==> Parameters: 1(Integer)
2020-09-27 13:42:56,160 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - <==      Total: 1
2020-09-27 13:42:56,160 INFO [CacheDateTest] - 方法执行前,查询结果:UserInfo(id=1, name=赵一, age=21)
2020-09-27 13:42:56,160 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==>  Preparing: select id, name, age from user_info where id = ? 
2020-09-27 13:42:56,161 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==> Parameters: 1(Integer)
2020-09-27 13:42:56,161 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==>  Preparing: select id, name, age from user_info where id = ? 
2020-09-27 13:42:56,162 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==> Parameters: 1(Integer)
2020-09-27 13:42:56,162 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - <==      Total: 1
2020-09-27 13:42:56,163 INFO [CacheDateTest] - 方法执行后,查询结果:UserInfo(id=1, name=赵一, age=21)
2020-09-27 13:42:56,163 INFO [CacheDateTest] - 方法执行前后,查询结果是否相同:false

查看日志打印,在执行这三个方法后,缓存会被清空,跟踪代码发现,这三个方法都是调用的DefaultSqlSession类中update()方法,并而且再深入,在BaseExecutor类中update()方法中会调用clearLocalCache()方法来清除缓存,所以在MyBatis一级缓存中,不会有更新的操作,只有新增和删除。

1.3 SQLSession执行clearCache()方法

示例代码

@Test
public void clearCacheTest() throws IOException {
        SqlSession sqlSession = this.getSqlSession();
        UserInfo userInfo1 = sqlSession.selectOne("org.yoko.com.dao.UserInfoDao.queryById1", 1);
        logger.info("方法执行前,查询结果:" + userInfo1);

        sqlSession.clearCache();

        UserInfo userInfo2 = sqlSession.selectOne("org.yoko.com.dao.UserInfoDao.queryById1", 1);
        logger.info("方法执行后,查询结果:" + userInfo2);
        logger.info("方法执行前后,查询结果是否相同:" + (userInfo1 == userInfo2));
}

控制台日志打印

2020-09-27 13:54:11,672 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==>  Preparing: select id, name, age from user_info where id = ? 
2020-09-27 13:54:11,701 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==> Parameters: 1(Integer)
2020-09-27 13:54:11,719 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - <==      Total: 1
2020-09-27 13:54:11,720 INFO [CacheDateTest] - 方法执行前,查询结果:UserInfo(id=1, name=赵一, age=21)
2020-09-27 13:54:11,722 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==>  Preparing: select id, name, age from user_info where id = ? 
2020-09-27 13:54:11,723 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - ==> Parameters: 1(Integer)
2020-09-27 13:54:11,725 DEBUG [org.yoko.com.dao.UserInfoDao.queryById1] - <==      Total: 1
2020-09-27 13:54:11,725 INFO [CacheDateTest] - 方法执行后,查询结果:UserInfo(id=1, name=赵一, age=21)
2020-09-27 13:54:11,725 INFO [CacheDateTest] - 方法执行前后,查询结果是否相同:false

在执行clearCache()方法后,一级缓存会被清空,跟踪代码,该方法底层是直接调用的BaseExecutor类中的clearLocalCache()方法来清空缓存。

二 Spring事务管理MyBatis

Spring框架集成MyBatis框架,业务示例代码

@Transactional
public void testWithTranscation() {
        UserInfo user1 = this.userInfoDao.queryById1(1);
        System.out.println("开启事务管理,第一次查询:" + user1);

        UserInfo user2 = this.userInfoDao.queryById1(1);
        System.out.println("开启事务管理,第二次查询:" + user2);

        System.out.println("开启事务管理,第一次查询结果是否和第二次查询结果相同:" + (user1 == user2));
}

public void testWithoutTranscation() {
        UserInfo user1 = this.userInfoDao.queryById1(1);
        System.out.println("未开启事务管理,第一次查询:" + user1);

        UserInfo user2 = this.userInfoDao.queryById1(1);
        System.out.println("未开启事务管理,第二次查询:" + user2);

        System.out.println("未开启事务管理,第一次查询结果是否和第二次查询结果相同:" + (user1 == user2));
}

测试代码

@Test
public void test() {
        this.userTempService.testWithTranscation();
        System.out.println("*********************** 分割线 ***********************");
        this.userTempService.testWithoutTranscation();
}

控制台日志打印

开启事务管理,第一次查询:UserInfo(id=1, name=赵一, age=21)
开启事务管理,第二次查询:UserInfo(id=1, name=赵一, age=21)
开启事务管理,第一次查询结果是否和第二次查询结果相同:true
*********************** 分割线 ***********************
未开启事务管理,第一次查询:UserInfo(id=1, name=赵一, age=21)
未开启事务管理,第二次查询:UserInfo(id=1, name=赵一, age=21)
未开启事务管理,第一次查询结果是否和第二次查询结果相同:false

MyBatis与Spring集成,在开启事务管理情况下,在一个事务内,Spring通过ThreadLocal始终使用同一个Session,所以一级缓存有效;未开启事务管理,每次请求Spring都会关闭旧的Session,再创建新的Session,所以这时一级缓存无效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值