Level 1 Cache
Mybatis supports caching, but by default without configuration, it only turns on the first level cache, which is relative to the same SqlSession.So when we invoke a Mapper method using the same SqlSession object with exactly the same parameters and SQL, we usually execute SQL only once, because after the first query using SelSession, MyBatis puts it in the cache, and when we query later, SqlSession pulls out the current cache if there is no declaration that refresh is required and the cache has not timed outData without sending SQL to the database again.
Why use a first-level cache? You don't have to say much about it.But there are a few more questions we need to be aware of.
1. How long is the lifetime of the first level cache?
A. MyBatis creates a new SqlSession object when opening a database session and a new Executor object in the SqlSession object.A new PerpetualCache object is held in the Executor object; when the session ends, the SqlSession object, its internal Executor object, and the PerpetualCache object are also released.
b. If SqlSession calls the close() method, the first-level cache PerpetualCache object will be released and the first-level cache will not be available.
c. If SqlSession calls clearCache(), the data in the PerpetualCache object is emptied, but the object is still available.
Any update operation (update(), delete(), insert () performed in d, SqlSession will empty the data of the PerpetualCache object, but the object can continue to use
2. How can I tell if a query or two queries are identical?
mybatis holds that for two queries, if the following conditions are identical, they are considered identical twice.
2.1 Incoming statementId
Result range in result set required for 2.2 query
2.3. The Sql statement string (boundSql.getSql()) that will eventually be passed to JDBC java.sql.Preparedstatement as a result of this query
2.4 Parameter values passed to java.sql.Statement to set
Secondary Cache:
MyBatis's secondary cache is an Application-level cache, which improves the efficiency of database queries to improve application performance.
The overall design of MyBatis's caching mechanism and the working mode of secondary caching
Secondary caches at the SqlSessionFactory level are not open by default, and the opening of secondary caches needs to be configured. When implementing secondary caches, MyBatis requires that POJO s returned be serializable.That is, the Serializable interface is required to be implemented. The configuration method is simple. Just map the XML file configuration to turn on the cache <cache/>. If we configure a secondary cache, that means:
- All select statements in the mapping statement file will be cached.
- The desired insert, update, and delete statements in the mapping statement file refresh the cache.
- The cache is retracted using the default LRU algorithm.
- Depending on the schedule, such as No Flush Interval (CNFI has no refresh interval), the cache does not refresh in any chronological order.
- The cache stores 1024 references to a list collection or object, regardless of what the query method returns
- Caches are treated as read/write (read/write) caches, meaning that object retrieval is not shared and can be safely modified by the callee without interfering with potential modifications made by other callers or threads.
Practice:
1. Create a POJO Bean and serialize it
Because secondary cached data is not always stored in memory, and there are many different storage media, it is necessary to serialize the cached objects.(Actual measurement without serialization is also possible if stored in memory.)
package com.yihaomen.mybatis.model; import com.yihaomen.mybatis.enums.Gender; import java.io.Serializable; import java.util.List; /** * @ProjectName: springmvc-mybatis */ @Data public class Student implements Serializable{ private static final long serialVersionUID = 735655488285535299L; private String id; private String name; private int age; private Gender gender; private List<Teacher> teachers; }
2. Turn on the secondary cache in the mapping file
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.yihaomen.mybatis.dao.StudentMapper"> <!--Open Book mapper Of namespace Second level cache under--> <!-- eviction:Represents the cache recycling policy, currently MyBatis Provide the following strategies. (1) LRU,The least recently used, the longest unused object (2) FIFO,FIFO removes objects in the order they enter the cache (3) SOFT,Soft reference, removing objects based on garbage collector status and soft reference rules (4) WEAK,Weak references, more aggressive removal of objects based on garbage collector status and weak reference rules.Here is the LRU, //Remove images you haven't used for the longest time flushInterval:The refresh interval, in milliseconds, is configured here as a 100-second refresh. If you do not configure it, then when SQL The cache will not refresh until it is executed. size:The number of references, a positive integer, represents the maximum number of objects that can be stored in the cache and should not be set too large.Setting up too much can cause memory overflow. //1024 objects are configured here readOnly:Read-only means that the cached data can only be read and not modified. The advantage of this setting is that we can read the cache quickly, but the disadvantage is that we don't have //Method to modify the cache, its default value is false, we are not allowed to modify --> <cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/> <resultMap id="studentMap" type="Student"> <id property="id" column="id" /> <result property="name" column="name" /> <result property="age" column="age" /> <result property="gender" column="gender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler" /> </resultMap> <resultMap id="collectionMap" type="Student" extends="studentMap"> <collection property="teachers" ofType="Teacher"> <id property="id" column="teach_id" /> <result property="name" column="tname"/> <result property="gender" column="tgender" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/> <result property="subject" column="tsubject" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/> <result property="degree" column="tdegree" javaType="string" jdbcType="VARCHAR"/> </collection> </resultMap> <select id="selectStudents" resultMap="collectionMap"> SELECT s.id, s.name, s.gender, t.id teach_id, t.name tname, t.gender tgender, t.subject tsubject, t.degree tdegree FROM student s LEFT JOIN stu_teach_rel str ON s.id = str.stu_id LEFT JOIN teacher t ON t.id = str.teach_id </select> <!--You can set useCache To specify this sql Whether to turn on caching, ture Yes, false Is off--> <select id="selectAllStudents" resultMap="studentMap" useCache="true"> SELECT id, name, age FROM student </select> <!--Refresh Level 2 Cache <select id="selectAllStudents" resultMap="studentMap" flushCache="true"> SELECT id, name, age FROM student </select> --> </mapper>
3. Open secondary cache in mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <!--This configuration makes the global mapper(Secondary Cache)Enable or disable caching--> <setting name="cacheEnabled" value="true" /> ..... </settings> .... </configuration>
IV. Testing
package com.yihaomen.service.student; import com.yihaomen.mybatis.dao.StudentMapper; import com.yihaomen.mybatis.model.Student; import com.yihaomen.mybatis.model.Teacher; import com.yihaomen.service.BaseTest; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import java.util.List; /** * * @ProjectName: springmvc-mybatis */ public class TestStudent extends BaseTest { public static void selectAllStudent() { SqlSessionFactory sqlSessionFactory = getSession(); SqlSession session = sqlSessionFactory.openSession(); StudentMapper mapper = session.getMapper(StudentMapper.class); List<Student> list = mapper.selectAllStudents(); System.out.println(list); System.out.println("Second Execution"); List<Student> list2 = mapper.selectAllStudents(); System.out.println(list2); session.commit(); System.out.println("Secondary Cache Observation Points"); SqlSession session2 = sqlSessionFactory.openSession(); StudentMapper mapper2 = session2.getMapper(StudentMapper.class); List<Student> list3 = mapper2.selectAllStudents(); System.out.println(list3); System.out.println("Second Execution"); List<Student> list4 = mapper2.selectAllStudents(); System.out.println(list4); session2.commit(); } public static void main(String[] args) { selectAllStudent(); } }
Result:
[QC] DEBUG [main] org.apache.ibatis.transaction.jdbc.JdbcTransaction.setDesiredAutoCommit(98) | Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@51e0173d] [QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | ==> Preparing: SELECT id, name, age FROM student [QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | ==> Parameters: [QC] DEBUG [main] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(139) | <== Total: 6 [Student{id='1', name='Lau Andy', age=55, gender=null, teachers=null}, Student{id='2', name='Zhang Huimei', age=49, gender=null, teachers=null}, Student{id='3', name='Nicholas Tse', age=35, gender=null, teachers=null}, Student{id='4', name='Wong Fei', age=47, gender=null, teachers=null}, Student{id='5', name='Wang Feng', age=48, gender=null, teachers=null}, Student{id='6', name='Zhang Ziyi', age=36, gender=null, teachers=null}] //Second Execution [QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.0 [Student{id='1', name='Lau Andy', age=55, gender=null, teachers=null}, Student{id='2', name='Zhang Huimei', age=49, gender=null, teachers=null}, Student{id='3', name='Nicholas Tse', age=35, gender=null, teachers=null}, Student{id='4', name='Wong Fei', age=47, gender=null, teachers=null}, Student{id='5', name='Wang Feng', age=48, gender=null, teachers=null}, Student{id='6', name='Zhang Ziyi', age=36, gender=null, teachers=null}] //Secondary Cache Observation Points [QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.3333333333333333 [Student{id='1', name='Lau Andy', age=55, gender=null, teachers=null}, Student{id='2', name='Zhang Huimei', age=49, gender=null, teachers=null}, Student{id='3', name='Nicholas Tse', age=35, gender=null, teachers=null}, Student{id='4', name='Wong Fei', age=47, gender=null, teachers=null}, Student{id='5', name='Wang Feng', age=48, gender=null, teachers=null}, Student{id='6', name='Zhang Ziyi', age=36, gender=null, teachers=null}] //Second Execution [QC] DEBUG [main] org.apache.ibatis.cache.decorators.LoggingCache.getObject(62) | Cache Hit Ratio [com.yihaomen.mybatis.dao.StudentMapper]: 0.5 [Student{id='1', name='Lau Andy', age=55, gender=null, teachers=null}, Student{id='2', name='Zhang Huimei', age=49, gender=null, teachers=null}, Student{id='3', name='Nicholas Tse', age=35, gender=null, teachers=null}, Student{id='4', name='Wong Fei', age=47, gender=null, teachers=null}, Student{id='5', name='Wang Feng', age=48, gender=null, teachers=null}, Student{id='6', name='Zhang Ziyi', age=36, gender=null, teachers=null}] Process finished with exit code 0
As we can see from the results, sql only executed once, proving that our secondary cache is working.
Source address: https://gitee.com/huayicompany/springmvc-mybatis
Reference resources:
[1] Yang Kaizhen, Deeply Understanding MyBatis Technology Principles and Practice, Electronic Industry Press, 2016.09
[2] Blog, http://blog.csdn.net/luanlouis/article/details/41280959
[3] Blog, http://www.cnblogs.com/QQParadise/articles/5109633.html
[4] Blog, http://blog.csdn.net/isea533/article/details/44566257