Mybatis一、二级缓存和自定义缓存

1,一级缓存

Mybatis默认开启一级缓存,一级缓存是在sqlSession层面进行缓存的。即,同一个sqlSession,多次调用同一个mapper和同一个方法的同一个参数,只会进行一次数据库查询,然后把数据缓存到缓冲中,以后查询直接从缓存中去查询,而不会直接查询数据库。

但是不同的sqlSession对象,因为不同的sqlSession都是相互隔离的,所以相同的Mapper、参数和方法,他还是会再次发送sql到数据库去执行,返回结果。

public static void main(String[] args) { // 自定义的单例SqlSessionFactory模式 SqlSessionFactory factory = SqlSessionFactoryUtil.openSqlSession(); // 获得SqlSession对象 SqlSession sqlSession = factory.openSession(); // 获得dao实体 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 进行两次相同的查询操作 userMapper.selectByPrimaryKey(1); userMapper.selectByPrimaryKey(1); // 注意,当我们使用二级缓存时候,sqlSession需要使用commit时候才会生效 sqlSession.commit(); System.out.println("\n\n============================================================="; // 获得一个新的SqlSession 对象 SqlSession sqlSession1 = factory.openSession(); // 进行相同的查询操作 sqlSession1.getMapper(UserMapper.class).selectByPrimaryKey(1); // 注意,当我们使用二级缓存时候,sqlSession需要使用commit时候才会生效 sqlSession.commit(); }

日志输出

DEBUG [main] - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@77caeb3e] DEBUG [main] - ==> Preparing: select user_ID, login_name,user_name, user_code, user_type, user_active, organization_ID,user_position,password from user where user_ID = ? DEBUG [main] - ==> Parameters: 1(Integer) TRACE [main] - <== Columns: user_ID, login_name, user_name, user_code, user_type, user_active, organization_ID, user_position, password TRACE [main] - <== Row: 1, ASH-001, 小明, JIKF-001, ADMIN, 1, 0, 销售员, 1212121212121 DEBUG [main] - <== Total: 1 ============================================================= DEBUG [main] - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@553f17c] DEBUG [main] - ==> Preparing: select user_ID, login_name,user_name, user_code, user_type, user_active, organization_ID,user_position,password from user where user_ID = ? DEBUG [main] - ==> Parameters: 1(Integer) TRACE [main] - <== Columns: user_ID, login_name, user_name, user_code, user_type, user_active, organization_ID, user_position, password TRACE [main] - <== Row: 1, ASH-001, 小明, JIKF-001, ADMIN, 1, 0, 销售员, 1212121212121 DEBUG [main] - <== Total: 1

从上面的日志可以看出,第一次的两次查询操作只执行了一个sql查询数据库;后面的查询操作又执行了一次数据库操作。

 

2,二级缓存

为了克服这个(不同sqlSession发起多次请求)问题,需要开启二级缓存,缓存在sqlSessionFaction对象共享。默认二级缓存是不开启的,需要手动进行配置。

如果配置的话,很多其他的配置就会默认进行,如:

* 映射文件的所有selelct语句会被缓存。

* 映射文件的所有的insert、update和delete语句会刷新缓存。

* 缓存会使用默认的Least Recently Used(LRU,最近最少使用原则)的算法来回收缓存空间

* 根据时间表,比如No Flush Internal,(CNFI,没有刷新间隔),缓存不会以任何时间顺序来刷新。

* 缓存会存储列表集合或对象的1024个引用

* 缓存可以被视为是read/white(可读/可写)的缓存,意味着对象检索不是共享的,而且可以很安全的被调用者修改,不干扰其他调用者或线程所作的潜在修改

添加后日志打印如下,可以发现所有过程只使用了一次数据库查询

EBUG [main] - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@5622fdf] DEBUG [main] - ==> Preparing: select user_ID, login_name,user_name, user_code, user_type, user_active, organization_ID,user_position,password from user where user_ID = ? DEBUG [main] - ==> Parameters: 1(Integer) TRACE [main] - <== Columns: user_ID, login_name, user_name, user_code, user_type, user_active, organization_ID, user_position, password TRACE [main] - <== Row: 1, AS-01, 小明, HJ-009, ADMIN, 1, 0, 销售员, dasfasdfasdfsdf DEBUG [main] - <== Total: 1 =============================================================

可以开启二级缓存的时候,手动配置一些属性

 

各个属性意义如下:

*eviction:缓存回收策略

-LRU:最少使用原则,一处最长时间不适用的对象

-FIFO:先进先出原则,按照对象进入缓存顺序进行回收。

-SOFT:软引用,移除基于垃圾回收器状态和软引用规则的对象。

-WEAK:弱引用,更积极的基于垃圾回收期和弱引用规则的对象。

* flushInterval:刷新时间间隔,单位为毫秒,这里配置的为100毫秒。如果不配合,那么只有在进行数据库修改操作才会被动刷新到缓存区。

* size:引用额数目,代表缓存最多可以存储的对象个数。

* readOnly:是否只读,如果为true,则所有相同的sql语句返回的是同一个对象(有助于提高性能),但并发操作同一条数据时,可能不安全),如果设置为false,则相同的sql,后面访问的是cache的clone副本。

* useCache配置

​ 如果一条语句每次都需要最新的数据,就意味着每次都需要从数据库中查询数据,可以把这个属性设置为false,如: