总述
简单来说就是通过开启一个sqlSession会话,通过jdk的动态代理方法获取对应mapper的代理实例对象,然后通过这个代理对象的invoke()方法执行MapperMethod对象方法。因为sqlSession之间一级缓存是隔离的,所以开启多个sqlSession后各自的一级缓存内容池是不一样的。invoke()执行后会根据id生成一个key,先去一级缓存查询有无对应key的缓存结果,如果没有就去执行DB操作查询解析出的sql结果,然后先移除缓存再插入。mybatis是如何知道我这个方法是delete/select/insert/update呢?这个是在执行invoke()时会讲mapper对应的xml配置文件传入的,它会解析这个方法对应的sqlType。具体可以看一下下面的解析过程。
第一阶段获取mapper动态代理阶段
@Test
public void testSecondCache() {
User user4 = userMapper.getUserById(2L);
System.out.println("----真实查询-----user4 = " + user4 + "\n");
sqlSession.commit(); //当使用二级缓存的时候,只有调用了commit方法后才会生效。
User user5 = userMapper.getUserById(2L);
System.out.println("----缓存查询-----user5 = " + user5 + "\n");
// 开启了新的sqlSession,则无法利用一级缓存,因为一级缓存是sqlSession之间隔离的
sqlSession = SqlSessionFactoryUtil.openSqlSession();
//开启新的sqlSession后,正式开始执行mybatis的过程,解析如下两行
userMapper = sqlSession.getMapper(UserMapper.class);
User user6 = userMapper.getUserById(2L);
System.out.println("----缓存查询-----user6 = " + user6);
}
第二阶段获取mapperMethod对象
@Test
public void testSecondCache() {
User user4 = userMapper.getUserById(2L);
System.out.println("----真实查询-----user4 = " + user4 + "\n");
sqlSession.commit(); //当使用二级缓存的时候,只有调用了commit方法后才会生效。
User user5 = userMapper.getUserById(2L);
System.out.println("----缓存查询-----user5 = " + user5 + "\n");
sqlSession = SqlSessionFactoryUtil.openSqlSession();
userMapper = sqlSession.getMapper(UserMapper.class);
//通过第一阶段获取的mapper代理实例对象,执行代理的invoke方法(代理对象必须从invoke()方法执行)
User user6 = userMapper.getUserById(2L);
System.out.println("----缓存查询-----user6 = " + user6);
}
第三阶段根据sql指令跳转执行语句
第四阶段查询前的缓存处理
//获取缓存key后从一级缓存中查询是否有结果,有就返回没有就执行db查询如何更新缓存
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
Cache cache = ms.getCache();
if (cache != null) {
this.flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
this.ensureNoOutParams(ms, parameterObject, boundSql);
List<E> list = (List)this.tcm.getObject(cache, key);
if (list == null) {
list = this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
this.tcm.putObject(cache, key, list);
}
return list;
}
}
return this.delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}