This is the 11th article in mybatis series. ** Did not see the previous article to go to [Java tomb Fox] public number to view the previous article, easy to understand and master.

What is caching?

Cache is a place to store data (referred to as: the Cache), when the program is to read the data, the first from the Cache, there are direct return, or obtained from the other storage devices, the Cache is the most important thing is obtained from its internal data speed is very fast, by caching can accelerate the access speed of data. For example, when we get data from DB, it takes time to transfer it through the network, and when the DB server reads data from disk, etc. If these data are directly stored in the corresponding memory of JVM, will the access be much faster?

Cache in Mybatis

Mybatis is divided into level 1 cache and level 2 cache.

  • Level 1 cache is the SqlSession level cache. The SqlSession object is required to operate the database. In the object, there is a data structure (HashMap) used to store cached data.
  • Level 2 cache is mapper level cache, multiple SQLsessions to operate the SAME MAPper SQL statement, multiple SQLsessions can share level 2 cache, level 2 cache is cross-SQLSession.

Level 1 cache

Level 1 cache is SqlSession level cache, each SqlSession has its own level 1 cache, multiple SQLsessions between level 1 cache is isolated from each other, do not affect each other, Mybatis level 1 cache is automatically enabled by default.

Level 1 cache works as follows: In the same SqlSession to many times to perform the same query, each will go to level 1 cache lookup, if the cache is returned directly, if there are no relevant data in a cache, mybatis will be for a lookup in the db, then will look up to the data in the cache, execute the same query for the second time, It finds that it already exists in the cache and returns it. The storage medium of level 1 cache is memory, which uses a HashMap to store data, so the access speed is very fast.

Level 1 Cache case

Case SQL script
DROP DATABASE IF EXISTS `mybatisdemo`; CREATE DATABASE `mybatisdemo`; USE `mybatisdemo`; DROP TABLE IF EXISTS user; CREATE TABLE user(id int AUTO_INCREMENT PRIMARY KEY COMMENT 'id', Name VARCHAR(32) NOT NULL DEFAULT 'COMMENT ', age SMALLINT NOT NULL DEFAULT 1 COMMENT' age ') COMMENT 'user table '; INSERT INTO t_user VALUES (1, 'Java burial fox, 18), (2,' Java ', 100), (3, 'burial fox, 23).Copy the code
The following is a query for user information, returning a list
<select id="getList1" resultType="com.zhonghu.chat12.demo9.model.UserModel" parameterType="map"> SELECT id,name,age FROM  user <where> <if test="id! =null"> AND id = #{id} </if> <if test="name! =null and name.toString()! =''"> AND name = #{name} </if> <if test="age! =null"> AND age = #{age} </if> </where> </select>Copy the code
Corresponding mapper interface method
List<UserModel> getList1(Map<String, Object> paramMap);
Copy the code
The test case
Com. Zhonghu. Chat12. Demo9. Demo9Test # level1CacheTest1 / l1 Test * * * * * @ throws IOException * / @ Test public void level1CacheTest1() throws IOException { String mybatisConfig = "demo9/mybatis-config.xml"; this.before(mybatisConfig); try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<UserModel> userModelList1 = mapper.getList1(null); log.info("{}", userModelList1); List<UserModel> userModelList2 = mapper.getList1(null); log.info("{}", userModelList2); log.info("{}", userModelList1 == userModelList2); }}Copy the code

The above code in the same SqlSession to execute 2 times to obtain the user list information, 2 times the query results are placed in userModelList1 and userModelList2, the final code will also determine whether these two sets of equal, let’s run to see how many times the db access.

Run the output
01:15. 312. [the main] the DEBUG C.J.C.D.M apper. UserMapper. GetList1 - = = > Preparing: SELECT id, name, age FROM user 01:15, 340 [main] the DEBUG C.J.C.D.M apper. UserMapper. GetList1 - = = > the Parameters: 01:15. 364. [the main] the DEBUG C.J.C.D.M apper. UserMapper. GetList1 - < = = Total: 3 01:15. [the main] 364 INFO C.J.C hat05. Demo9. Demo9Test - [UserModel (id = 1, name = Java burial fox, age = 18), UserModel (id = 2, name = Java, Age = 100), UserModel (id = 3, the name = mound fox, age 23) =] 01:15. [the main] 367 INFO C.J.C hat05. Demo9. Demo9Test - [UserModel (id = 1, Name =Java, age=18), UserModel(id=2, name=Java, age=100), UserModel(id=3, name=Java, age=100), Age = 23)] 01:15. 367. [the main] INFO C.J.C hat05. Demo9. Demo9Test - trueCopy the code

The first time the database is accessed, the second time the database is directly retrieved from the cache, and the last time the output is true. The second time the database is directly retrieved from the cache, which speeds up the query speed.

Three ways to clear level 1 cache

The same SqlSession to query the same data, mybatis will get from the level cache by default, if not in the cache, will access db, so if we want to not go to the cache but directly to access the database, and how to operate?

There are three ways to invalidate level 1 cache:

  • SqlSession adds, deletes, and modifies data, and the SqlSession automatically clears level-1 cache
  • Call the clearCache method in SqlSession to clean its internal level 1 cache
  • Set the value of the flushCache attribute in the Mapper XML select element to true. In this case, all data in the level-1 cache will be flushed before the database is used to obtain data

Either of the above methods invalidates the current SqlSession and cache, and the database is fetched.

Level 1 caching uses summary

  • Level 1 cache is the SqlSession level. Each SqlSession has its own Level 1 cache, and different SQLsessions are isolated from each other
  • Level 1 caching in Mybatis is automatically enabled by default
  • When the same query is executed in the same SqlSession, it is searched from the level-1 cache first. If it is found, it is returned directly. If it is not found, the database is accessed, and the data returned by the DB is thrown into the level-1 cache
  • There are three ways to clear level-1 cache. (1) Level-1 cache will be invalid if you add, delete, or modify the cache in SqlSession. 2: Calling sqlsession. clearCache invalidates level 1 cache. FlushCache invalidates the level 1 cache when the select element in Mapper XML is set to true

The second level cache

Use of level 2 cache

Level 1 cache has limitations in use, you must execute the same query in the same SqlSession, level 1 cache can improve the query speed, if you want to use cache between different SQLsessions to speed up the query, at this time we need to use level 2 cache.

Level 2 cache is mapper level cache, each MAPper XML has a namespace, level 2 cache and namespace bound, each namespace is associated with a level 2 cache, multiple SQLSessions can share level 2 cache, level 2 cache is cross-SQLSession.

Level 2 cache is not enabled by default, we need to enable it in mybatis global configuration file:

<settings> <! <setting name="cacheEnabled" value="true"/> </ Settings >Copy the code

Add the following configuration to mapper XML to enable level 2 caching for queries in this mapper:

<cache/>
Copy the code

Configuration is as simple as that.

Query principle when primary and secondary caches coexist

If both the primary and secondary caches are enabled, the data query process is as follows:

  • When launching a query, Mybatis will first access the level 2 cache corresponding to the namespace. If there is data in the level 2 cache, myBatis will directly return the data. Otherwise, it will continue down
  • Query whether the corresponding data exists in the level-1 cache. If yes, return the data directly. Otherwise, proceed to the next step
  • Access db to get the required data, place it in the level 2 cache corresponding to the current SqlSession, and store a copy in local memory in another location (this is called TransactionalCache).
  • When SqlSession is closed, that is, when SqlSession’s close method is called, the TransactionalCache data is put into level 2 cache and the current SqlSession level 1 cache is emptied.

Level 2 Cache Case

Mybatis Global Profile enables level 2 cache configuration
<settings> <! <setting name="cacheEnabled" value="true"/> </ Settings >Copy the code
Mapper XML uses the cache element to enable level 2 caching
<! - to enable the second level cache - > < cache / > < select id = "getList1" resultType = "com. Zhonghu. Chat12. Demo9. Model. UserModel" parameterType = "map" > SELECT id,name,age FROM user <where> <if test="id! =null"> AND id = #{id} </if> <if test="name! =null and name.toString()! =''"> AND name = #{name} </if> <if test="age! =null"> AND age = #{age} </if> </where> </select>Copy the code
The test case
Com. Zhonghu. Chat12. Demo9. Demo9Test # level2CacheTest1 / level 2 cache Test * * * * * @ throws IOException * / @ Test public void level2CacheTest1() throws IOException { String mybatisConfig = "demo9/mybatis-config1.xml"; this.before(mybatisConfig); for (int i = 0; i < 2; i++) { try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<UserModel> userModelList1 = mapper.getList1(null); log.info("{}", userModelList1); }}}Copy the code

Two queries were executed above, each with a new SqlSession.

Three ways to clear or skip a level 2 cache

When level 2 cache is enabled, all queries in mapper XML are enabled by default after the cache element is added. How do we clear or skip level 2 cache? The three methods are as follows:

  • Add, delete, modify, and search in the corresponding Mapper will clear the data in the level-2 cache
  • Set the select element’s flushCache attribute to true to flush the data in the level-2 cache, then query the data in the DB, and then put the data in the level-2 cache
  • The select element’s useCache attribute is set to true to enable the query to skip the secondary cache and query for data

conclusion

  • The access order of the primary and secondary caches: if both the primary and secondary caches exist, the secondary cache will be accessed first, then the level-1 cache will be accessed, and finally db will be accessed

  • Set the flushCache attribute of the mapper XML select element to false to flush all data in the level-1 cache and in the level-2 cache of the namespace in which the select element belongs

  • Setting the useCache of the mapper XML select element to false causes the query to skip the second-level cache

  • Generally speaking, the use of cache can improve query efficiency, this knowledge is mastered, you can choose according to the business

    The last

    • If you feel that you have gained something after watching it, I hope you can pay attention to it and give me a “like”, which will be the biggest motivation for my update. Thank you for your support
    • Welcome everyone to pay attention to my public number [Java tomb Fox], focus on Java and computer basic knowledge, to ensure that you see something harvest, do not believe you hit me
    • Ask for a key three even: like, forward, look.
    • If you have different opinions or suggestions after reading, welcome to comment together. Thank you for your support and kindness.

    I’m Tsuka Fox. I love programming as much as you do.

Please follow the public account “Java Tomb Fox” for the latest news