Mybatis Cache-Level 2 Cache

Keywords: Mybatis SQL

Mybatis supports second-level caching in addition to first-level caching, which is namespace-level.

1. Level 2 cache

1.1 Level 2 Cache Characteristics

  • The second level cache is namespace level, which is superior to sqlSession and can share between sqlSessions.
  • Level 2 cache global configuration mode is open and can be turned off
  • The secondary cache is transactional, and when sqlSession closes or commits a transaction normally, the primary cache in sqlSession is refreshed to the secondary cache.
  • When a transaction rolls back, the first level cache in sqlSession does not refresh to the second level cache.

1.2 Open Level 2 Cache

  • The easiest way to open the cache is to add tags directly to the sql mapping file.
  • Note that entities that need to be cached need to implement serialized interfaces
<cache/>

1.3 Default Behavior of Cache Labels

Use its default configuration. Default caching features:

  • The results of all select statements in the mapping statement file will be cached. You can close the cache of select statements by setting useCache=false
  • All insert, update, and delete statements in the mapping statement file refresh the cache.
  • Caching uses the Least Current Used (LRU) algorithm to clear unnecessary caches.
  • The cache does not refresh regularly (that is, there is no refresh interval).
  • The cache stores 1024 references to a list or object, regardless of which query method returns.
  • Caches are considered read/write caches, which means that the acquired objects are not shared and can be safely modified by the caller without interfering with potential modifications made by other callers or threads.
<cache/>

1.4 cache tag attributes

The cache tag provides four attributes to customize the behavior of the default secondary cache:

  • Flush Interval: Sets the refresh interval, that is, the time to empty the cache, in milliseconds. By default, refresh when calling statements
  • size: Sets the maximum number of references to cached objects per namespace, defaulting to 1024.
  • readOnly: Sets whether the resulting cache is read-only.
    • true: Setting read-only will return the reference to the cache, which will be fast. But it is not safe because it can be modified.
    • false: Setting up read and write will generate new objects through deserialization, which will be slightly slower
  • eviction: Set cache clearance policy, default LRU.
    • LRU: Minimum Recent Use: Remove objects that have not been used for the longest time.
    • FIFO: First in, first out: Remove objects in the order they enter the cache.
    • SOFT: Soft reference: Removing objects based on garbage collector status and soft reference rules.
    • WEAK: Weak references: Remove objects more actively based on garbage collector status and weak reference rules.

2. Level 2 cache testing

2.1 Setting up Global Open Level 2 Cache

The global secondary cache is opened by default, or the declaration is displayed to open the global secondary cache.

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

2.2 Entities requiring caching implement serialized interfaces

Because caching requires serialized entities, entities must implement serialized interfaces.

public class EmployeePO implements Serializable {

    private static final long serialVersionUID = -2164461308545729638L;
    
    //...
}

2.3 Test Cases

  • Test Level 2 Cache Effectiveness: When sqlSession is closed, write Level 1 Cache in this sqlSession to Level 2 Cache
  • Test Level 2 Cache Effectiveness: When sqlSession commits a transaction, write Level 1 Cache in this sqlSession to Level 2 Cache
  • Test Level 2 cache is not valid: If useCache=false is set in the query, Level 2 cache is not valid
  • Test Level 2 Cache does not work: When sqlSession rolls back transactions, the cache in sqlSession is not written to Level 2 Cache
public class TestCacheLevel2 {


    // Test Level 2 Cache Effectiveness: When sqlSession is closed, write Level 1 Cache in this sqlSession to Level 2 Cache
    @Test
    public void test_valid1(){

        SqlSession sqlSession1 = SqlSessionUtil.openSession(false);
        SqlSession sqlSession2 = SqlSessionUtil.openSession(false);

        EmployeeMapper empMapper1 = sqlSession1.getMapper(EmployeeMapper.class);
        EmployeeMapper empMapper2 = sqlSession2.getMapper(EmployeeMapper.class);

        System.out.println("Make the first query...");
        EmployeePO emp1 = empMapper1.findById(1L);

        // When sqlSession closes, the first level cache is written to the second level cache.
        sqlSession1.close();

        System.out.println("Make a second inquiry...");
        EmployeePO emp2 = empMapper2.findById(1L);

        Assert.assertNotEquals(emp1, emp2);
    }

    // Test Level 2 Cache Effectiveness: When sqlSession commits a transaction, write Level 1 Cache in this sqlSession to Level 2 Cache
    @Test
    public void test_valid2(){

        SqlSession sqlSession1 = SqlSessionUtil.openSession(false);
        SqlSession sqlSession2 = SqlSessionUtil.openSession(false);

        EmployeeMapper empMapper1 = sqlSession1.getMapper(EmployeeMapper.class);
        EmployeeMapper empMapper2 = sqlSession2.getMapper(EmployeeMapper.class);

        System.out.println("Make the first query...");
        EmployeePO emp1 = empMapper1.findById(1L);

        // When sqlSession commits a transaction, the data in this sqlSession is written to the cache
        sqlSession1.commit();

        System.out.println("Make a second inquiry...");
        EmployeePO emp2 = empMapper2.findById(1L);

        Assert.assertNotEquals(emp1, emp2);
    }

    // Test Level 2 cache is not valid: If useCache=false is set in the query, Level 2 cache is not valid
    @Test
    public void test_invalid1(){

        SqlSession sqlSession1 = SqlSessionUtil.openSession(false);
        SqlSession sqlSession2 = SqlSessionUtil.openSession(false);

        EmployeeMapper empMapper1 = sqlSession1.getMapper(EmployeeMapper.class);
        EmployeeMapper empMapper2 = sqlSession2.getMapper(EmployeeMapper.class);

        System.out.println("Make the first query...");
        EmployeePO emp1 = empMapper1.findById(1L);

        // When sqlSession closes, the first level cache is written to the second level cache.
        sqlSession1.close();

        System.out.println("Make a second inquiry...");
        EmployeePO emp2 = empMapper2.findById(1L);

        Assert.assertNotEquals(emp1, emp2);
    }

    // Test Level 2 Cache does not work: When sqlSession rolls back transactions, the cache in sqlSession is not written to Level 2 Cache
    @Test
    public void test_invalid2(){

        SqlSession sqlSession1 = SqlSessionUtil.openSession(true);
        SqlSession sqlSession2 = SqlSessionUtil.openSession(true);

        EmployeeMapper empMapper1 = sqlSession1.getMapper(EmployeeMapper.class);
        EmployeeMapper empMapper2 = sqlSession2.getMapper(EmployeeMapper.class);

        System.out.println("Make the first query...");
        EmployeePO emp1 = empMapper1.findById(1L);

        // When sqlSession commits a transaction, the data in this sqlSession is written to the cache
        sqlSession1.rollback();

        System.out.println("Make a second inquiry...");
        EmployeePO emp2 = empMapper2.findById(1L);

        Assert.assertNotEquals(emp1, emp2);
    }

}

Posted by cdorob on Tue, 27 Aug 2019 02:15:28 -0700