MyBatis example - Cache

MyBatis provides two types of caches, one is a cache, the other is the secondary cache, the cache MyBatis chapter describes the use of by way of example.

Test categories: com.yjw.demo.CacheTest

Cache

MyBatis cache is enabled by default. Level cache is a SqlSession relative to the same terms, so in SQL parameters and exactly the same situation, we use the same method with a SqlSession object calls Mapper, often only once SQL, because the first query using SqlSession after, MyBatis will put it in the cache, and then later, when queried, if there is no statement needs to be refreshed, and the case did not cache timeout, SqlSession will only remove the currently cached data without sending SQL to the database again.

testing method:

/**
 * Cache
 */
@Test
public void l1Cache() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    long startTime1 = System.currentTimeMillis();
    sqlSession.selectList("com.yjw.demo.mybatis.biz.dao.StudentDao.listByConditions"); LOGGER.info ( "the first query execution time:" + (System.currentTimeMillis () - startTime1)); Long startTime2 = System.currentTimeMillis (); sqlSession.selectList ( "com.yjw.demo.mybatis.biz.dao .StudentDao.listByConditions " ); logger.info (" second query execution time: "+ (System.currentTimeMillis () - startTime2)); sqlSession.close ();}
2019-09-16 10:16:02.133  INFO 26268 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
2019-09-16 10:16:02.148 DEBUG 26268 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : ==>  Preparing: select id, name, sex, selfcard_no, note from t_student 
2019-09-16 10:16:02.210 DEBUG 26268 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : ==> Parameters: 
2019-09-16 10:16:02.242 DEBUG 26268 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : <==      Total: 3
2019-09-16 10: 16: 02.243 INFO 26268 --- [main] com.yjw.demo.CacheTest: the first query execution times: 825
2019-09-16 10: 16: 02.244 INFO 26268 --- [main] com.yjw.demo.CacheTest: The second query execution time: 1

Comparison of the contents of the log query twice, the second query does not execute SQL statements, apparently the second query is retrieved from the cache data.

Second-level cache (not recommended)

MyBatis default does not open the secondary cache. The secondary cache is SqlSessionFactory level, opening the secondary cache needs to be configured, when implementing secondary cache, MyBatis required POJO returned must be serializable, i.e. required to achieve Serializable interface, the method is very simple configuration, only you need to configure the mapping XML file <cache /> element can open the cache.

MyBatis is based on namespace secondary cache, the cache is a content stored namespace, it is considered namespace cache KEY value.

<cache />

Such a statement there, a lot is the default setting, so if we just configured, then it means:

  • All mapping select statement statement file will be cached;
  • All insert the mapped statement file, update and delete statements will refresh the cache;
  • Cache uses the default Least Recently Used (LRU, least recently used) algorithm for eviction;
  • According to the schedule, such as No Flush Interval, (CNFI, no refresh interval), the cache will not be any sort of time to refresh;
  • The cache will store lists or objects (whatever the query method returns) of the 1024 reference;
  • The cache will be treated as a read / write (read / write) cache, meaning objects retrieved are not shared and can be safely modified by the caller, the caller does not interfere with other potential modifications or threads made.

In addition, we also can <cache-res />be configured to implement a plurality of secondary cache share the same namespace, i.e. the same Cache object.

 

As shown above, namespace2 share of the Cache object namespace1.

A secondary cache and the cache can coexist, to be understood that two lower buffer structure by MyBatis FIG.

 

 

When the application executes operations defined in the query in the namespace namespace2 by SqlSession2, SqlSession2 first secondary cache namespace2 to find whether a cache corresponding to a respective result object. If not, proceed to the corresponding cache SqlSession2 find whether to cache the results of the corresponding object, if still not, you get access to the database and the result set is mapped to the result object returned. Finally, the result object records corresponding to SqlSession cache and secondary cache namespace2 corresponding, wait for subsequent use. Also note that the figure above and namespace3 namespace namespace2 share the same secondary cache object, perform exactly the same query in the namespace namespace3 by SqlSession3 (CacheKey as long as the query object is generated in the above-described SqlSession2 CacheKey same query generation to objects), the result object can be obtained directly from the corresponding secondary cache. 

Case:

We test cases secondary cache, the first entity class must implement the Serializable interface, add the following configuration in StudentMapper file:

<! - secondary cache ->
<cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true" />

testing method:

/**
 * Secondary cache
 */
@Test
public void l2Cache() {
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    long startTime1 = System.currentTimeMillis();
    sqlSession1.selectList("com.yjw.demo.mybatis.biz.dao.StudentDao.listByConditions", new new StudentQuery ()); logger.info ( "first query execution time SqlSession:" + (System.currentTimeMillis () - startTime1)); sqlSession1.commit (); sqlSession1.close (); SqlSession sqlSession2 = sqlSessionFactory.openSession (); Long startTime2 = System.currentTimeMillis (); sqlSession2.selectList ( "com.yjw.demo.mybatis.biz.dao.StudentDao.listByConditions" , new new StudentQuery ()); logger.info ( "second query SqlSession execution time: "+ (System.currentTimeMillis () - startTime2)); sqlSession2.commit (); sqlSession2.close ();}
09/16/2019 14: 33: 13 848 --- 22372 DEBUG [main] com.yjw.demo.mybatis.biz.dao.StudentDao: Cache Hit Ratio [com.yjw.demo.mybatis.biz.dao.StudentDao] : 0.0
2019-09-16 14:33:15.748  INFO 22372 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
2019-09-16 14:33:15.764 DEBUG 22372 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : ==>  Preparing: select id, name, sex, selfcard_no, note from t_student 
2019-09-16 14:33:15.844 DEBUG 22372 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : ==> Parameters: 
2019-09-16 14:33:15.885 DEBUG 22372 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : <==      Total: 3
2019-09-16 14: 33: 15.887 INFO 22372 --- [main] com.yjw.demo.CacheTest: a first query execution time SqlSession: 2304
09/16/2019 14: 33: 15 890 --- 22372 DEBUG [main] com.yjw.demo.mybatis.biz.dao.StudentDao: Cache Hit Ratio [com.yjw.demo.mybatis.biz.dao.StudentDao] : 0.5
2019-09-16 14: 33: 15.891 INFO 22372 --- [main] com.yjw.demo.CacheTest: SqlSession second query execution time:

As can be seen from the log, the second query does not execute SQL statements, also print the log cache command rate: Cache Hit Ratio, so the second Session of the Executive is to obtain data from the cache.

Detailed description secondary cache configuration:

<cache eviction="LRU" flushInterval="100000" size="1024" readOnly="true" />
  • eviction : cache recovery strategy, currently provide some MyBatis strategy;
  • The LRU : Least Recently Used, removing most of the objects do not have time;
  • The FIFO : FIFO, in order to remove the object thereof into the cache;
  • SOFT : soft references, remove objects based on the garbage collector state and the rules of the soft references;
  • WEAK : weak references, more aggressively removes objects based on the garbage collector state and rules of Weak References. Here is LRU, the maximum time an object is removed unused;
  • flushInterval : refresh interval time, in milliseconds, where the configuration of 100 seconds to refresh, if you do not configure it, then when SQL will be executed to refresh the cache;
  • size : the number of references, a positive integer representing the maximum number of cached objects can be stored, should not be set too high, are too long cause a memory leak, here is the configuration of the 1024 target;
  • readOnly : read-only, meaning that the cached data can only be read but not modify, the benefits of this set up is that we can quickly read cache, the disadvantage is that we have no way to modify the cache.

Secondary cache problems:

  • Dirty data : because the secondary cache is based namespace, such as exist in StudentMapper a query in SQL, it is associated with a student ID information query, this time to open a second-level cache, student ID will exist in the corresponding cache data StudentMapper If the data update student ID information, then StudentMapper on the existence of the dirty data;
  • All failure : insert, update and delete statements will refresh all cached data in the same namespace, refer to the following examples;
/**
 * Test all secondary cache failures, as long as the implementation of the insert, update, delete
 * Will refresh all cached data at the same namespace
 */
@Test
public void l2CacheInvalid() {
    // cache data listByConditions
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    long startTime1 = System.currentTimeMillis();
    sqlSession1.selectList("com.yjw.demo.mybatis.biz.dao.StudentDao.listByConditions", new new StudentQuery ()); logger.info ( "first SqlSession query execution time:" + (System.currentTimeMillis () - startTime1)); sqlSession1.commit (); sqlSession1.close (); // cache data of getByPrimaryKey = sqlSession2 the SqlSession sqlSessionFactory.openSession (); Long startTime2 = System.currentTimeMillis (); sqlSession2.selectList ( "com.yjw.demo.mybatis.biz.dao.StudentDao.getByPrimaryKey" , 1L ); logger.info ( "second a SqlSession query execution time: "+ (System.currentTimeMillis () - startTime2)); sqlSession2.commit (); sqlSession2.close (); // execute insert statement makes all of the above cache invalidation sqlSession3 = SqlSession sqlSessionFactory.openSession (); = new new studentDO studentDO studentDO (); studentDO.setName ( "Zhao six" ); studentDO.setSex (Sex.MALE); studentDO.setSelfcardNo(4444L); StudentDO.setNote ( "zhaoliu" ); sqlSession3.insert ( "com.yjw.demo.mybatis.biz.dao.StudentDao.insertByAutoInc" , studentDO); sqlSession3.commit (); sqlSession3.close (); // executed again above the cached data to see if the cache has been SqlSession sqlSession4 = failure sqlSessionFactory.openSession (); Long startTime4 = System.currentTimeMillis (); sqlSession4.selectList ( "com.yjw.demo.mybatis.biz.dao.StudentDao.listByConditions " , new new StudentQuery ()); logger.info (" fourth SqlSession query execution time: "+ (System.currentTimeMillis () - startTime4)); sqlSession4.commit (); sqlSession4.close (); // cache getByPrimaryKey data = sqlSession5 the SqlSession sqlSessionFactory.openSession (); Long startTime5 =System.currentTimeMillis (); sqlSession5.selectList ( "com.yjw.demo.mybatis.biz.dao.StudentDao.getByPrimaryKey" , 1L ); logger.info ( "Fifth SqlSession query execution time:" + (System.currentTimeMillis () - startTime5)); sqlSession5.commit (); sqlSession5.close ();}
09/16/2019 14: 47: 43 489 --- 14940 DEBUG [main] com.yjw.demo.mybatis.biz.dao.StudentDao: Cache Hit Ratio [com.yjw.demo.mybatis.biz.dao.StudentDao] : 0.0
2019-09-16 14:47:44.258  INFO 14940 --- [           main] com.alibaba.druid.pool.DruidDataSource   : {dataSource-1} inited
2019-09-16 14:47:44.274 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : ==>  Preparing: select id, name, sex, selfcard_no, note from t_student 
2019-09-16 14:47:44.328 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : ==> Parameters: 
2019-09-16 14:47:44.369 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : <==      Total: 3
2019-09-16 14: 47: 44.371 INFO 14940 --- [main] com.yjw.demo.CacheTest: first SqlSession query execution times: 1015
09/16/2019 14: 47: 44 377 --- 14940 DEBUG [main] com.yjw.demo.mybatis.biz.dao.StudentDao: Cache Hit Ratio [com.yjw.demo.mybatis.biz.dao.StudentDao] : 0.0
2019-09-16 14:47:44.378 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.getByPrimaryKey   : ==>  Preparing: select id, name, sex, selfcard_no, note from t_student where id = ? 
2019-09-16 14:47:44.380 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.getByPrimaryKey   : ==> Parameters: 1(Long)
2019-09-16 14:47:44.382 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.getByPrimaryKey   : <==      Total: 1
2019-09-16 14: 47: 44.383 INFO 14940 --- [main] com.yjw.demo.CacheTest: SqlSession second query execution time: 7
2019-09-16 14:47:44.383 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.insertByAutoInc   : ==>  Preparing: insert into t_student (name, sex, selfcard_no, note) values ( ?, ?, ?, ? ) 
2019-09-16 14:47:44.388 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.insertByAutoInc   : ==> Parameters: 赵六(String), 1(Integer), 4444(Long), zhaoliu(String)
2019-09-16 14:47:44.474 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.insertByAutoInc   : <==    Updates: 1
09/16/2019 14: 47: 44 476 --- 14940 DEBUG [main] com.yjw.demo.mybatis.biz.dao.StudentDao: Cache Hit Ratio [com.yjw.demo.mybatis.biz.dao.StudentDao] : 0.0
2019-09-16 14:47:44.477 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : ==>  Preparing: select id, name, sex, selfcard_no, note from t_student 
2019-09-16 14:47:44.477 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : ==> Parameters: 
2019-09-16 14:47:44.481 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.listByConditions  : <==      Total: 4
2019-09-16 14: 47: 44.481 INFO 14940 --- [main] com.yjw.demo.CacheTest: fourth SqlSession query execution time: 5
09/16/2019 14: 47: 44 482 --- 14940 DEBUG [main] com.yjw.demo.mybatis.biz.dao.StudentDao: Cache Hit Ratio [com.yjw.demo.mybatis.biz.dao.StudentDao] : 0.0
2019-09-16 14:47:44.483 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.getByPrimaryKey   : ==>  Preparing: select id, name, sex, selfcard_no, note from t_student where id = ? 
2019-09-16 14:47:44.483 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.getByPrimaryKey   : ==> Parameters: 1(Long)
2019-09-16 14:47:44.485 DEBUG 14940 --- [           main] c.y.d.m.b.d.StudentDao.getByPrimaryKey   : <==      Total: 1
2019-09-16 14: 47: 44.486 INFO 14940 --- [main] com.yjw.demo.CacheTest: fifth SqlSession query execution time: 4

As can be seen from the above information log, four times query operation, the SQL statement is executed, fourth and fifth query does not get data from the cache, because the third execution statement (insert) under the current namespace for all caches are ineffective.

Given the above two secondary cache issues, it is not recommended in the project MyBatis secondary cache.

 

MyBatis Practical Tips

MyBatis concept

MyBatis Example - Introduction

Example MyBatis - processor type

MyBatis example - a plurality of transmission parameters

Example MyBatis - primary key backfilling

MyBatis Example - Dynamic SQL

MyBatis example - joint inquiry

MyBatis example - Cache

MyBatis Example - plug-in

Guess you like

Origin www.cnblogs.com/yinjw/p/11757126.html