MyBatis cache is divided into level 1 cache and level 2 cache, the cache granularity of two kinds of cache is the same, both are corresponding to a SQL query statement, but the life cycle of the two is not the same, the life cycle of level 1 cache is during the use of SqlSession object, with the death of SqlSession object and disappear; The lifetime of level 2 cache is the same as that of MyBatis; Like most persistence frameworks, MyBatis also supports both level 1 and level 2 caching.

1. Cache: The storage scope of this Cache is Session. When a Session is flush or close, all caches in this Session are flushed.

2. The mechanism for tier-2 cache is the same as that for Tier-1 cache, which uses PerpetualCache and HashMap by default. The difference is that the storage scope is Mapper and the storage source can be customized, such as Ehcache. The level 2 cache is global in scope and does not take effect until SqlSession is closed or committed.

Based on the analysis of the second level cache of MyBatis before, we first look at the simple MyBatis in a class that is on the second level cache (other related classes and interfaces have been analyzed before) : org. Apache. Ibatis. Mapping. MappedStatement: The MappedStatement class is used in the Mybatis framework to represent an SQL statement node in an XML file, i.e., a, or tag. Mybatis framework will read THE XML configuration file in the initialization stage and convert SQL statement node objects into MappedStatement objects. If a C/U/D operation is performed on a Session (level 1) or Namespaces (level 2), all caches in the select area will be cleared by default. The level 1 cache function of Mybatis is that in the same session process, the access to the same data will not be through the database, but through the cache mechanism to improve efficiency.

Look at the test code

import java.io.IOException; import java.io.InputStream; import junit.framework.TestCase; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import com.guowuxin.mybatis.mapper.UserMapper; import com.guowuxin.mybatis.model.User;Copy the code
/* Drop tableifexists user; create table user( id int primary key auto_increment, username varchar(50) unique, password varchar(100), useraddress varchar(50)); insert into user values(1,"guowuxin"."guowuxin"."beijing"); insert into user values(1,"guoxiaoming"."guowuxin"."beijing"); * /Copy the code

If both queries are query 1, only one SQL statement will be sent to the database, otherwise two SQL statements will be sent to the database

public class TestClass extends TestCase{    public static SqlSessionFactory sqlSessionFactoy;    static{        String resource = "mybatis-config.xml";        try {            InputStream inputStream = Resources.getResourceAsStream(resource);            sqlSessionFactoy = new SqlSessionFactoryBuilder().build(inputStream);        } catch (IOException e) {            e.printStackTrace();        }    }    @Test     public void testgetUserById() { SqlSession sqlSession = sqlSessionFactoy.openSession(); try { UserMapper mapper = sqlSession.getMapper(UserMapper.class); User u1=mapper.getUserById(1); System.out.println(u1); User u2=mapper.getUserById(1); System.out.println(u2); sqlSession.commit(); } finally { sqlSession.close(); }}}Copy the code
package com.guowuxin.mybatis.mapper; import com.guowuxin.mybatis.model.User; Public interface UserMapper {public User getUserById(int ID); public User getUserById(int ID); public User getUserById(int id); }package com.guowuxin.mybatis.model; public class User { private int id; private int age; private String userName; private String userAddress; public intgetId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName;    }    public String getUserAddress() {        return userAddress;    }    public void setUserAddress(String userAddress) {        this.userAddress = userAddress;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString()    {        final StringBuilder builder = new StringBuilder();        builder.append("id=").append(id).append(",");        builder.append("age=").append(age).append(",");        builder.append("userName=").append(userName).append(",");        builder.append("userAddress=").append(userAddress).append(".");        return builder.toString();    }}Copy the code
log4 j. rootLogger = DEBUG, the Console ˆ †#Consolelog4j.appender.Console=org.apache.log4j.ConsoleAppenderlog4j.appender.Console.layout=org.apache.log4j.PatternLay outlog4j.appender.Console.layout.ConversionPattern=%d %t %-5p (%c) - %m%nlog4j.logger.com.ibatis=DEBUGlog4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUGlog4j.logger.com.ibatis.commo n.jdbc.ScriptRunner=DEBUGlog4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUGlog4j.logger.java.sql.Conn ection=DEBUGlog4j.logger.java.sql.Statement=DEBUGlog4j.logger.java.sql.PreparedStatement=DEBUGCopy the code
<? 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>    <typeAliases>        <typeAlias alias="User" type="com.guowuxin.mybatis.model.User" />    </typeAliases>    <environments default="development">        <environment id="development">            <transactionManager type="JDBC" />            <dataSource type="POOLED">                      <property name="driver" value="com.mysql.jdbc.Driver" />                    <property name="url" value="JDBC: mysql: / / 127.0.0.1:3306 / guowuxin" />                    <property name="username" value="root" />                    <property name="password" value="admin" />            </dataSource>        </environment>    </environments>    <mappers>         <mapper resource="UserMapper.xml"/> </mappers></configuration><? 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"> <! Namespace = PostsMapper interface = PostsMapper interface = PostsMapper interface = PostsMapper interface = PostsMapper interface = PostsMapper interface"com.guowuxin.mybatis.mapper.UserMapper"> <! Mybatis -config. XML --> <select id="getUserById" parameterType="int" resultType="User">            select * from user where id=#{id} Copy the code

Results:……………………… .

The 2016-02-24 20:12:37, 568 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - ooo Using Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:12:37, 568 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==> Preparing: select * from userwhereid=? The 2016-02-24 20:12:37, 586 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - = = > the Parameters: 1(Integer)id=1,age=0,userName=guowuxin,userAddress=beijing.id=1,age=0,userName=guowuxin,userAddress=beijing.2016-02-24 20:12:37, 593 main DEBUG (org. Apache. Ibatis. Transaction. JDBC. JdbcTransaction) - Resetting the autocommit mode totrueOn the JDBC Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:12:37, 593 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:12:37, 593 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Returned connection 3874052 to pool.Copy the code

If you get two different ids ………………… .

The 2016-02-24 20:12:57, 655 main DEBUG (org. Apache. Ibatis. The datasource. Pooled. PooledDataSource) - Created the connection 3874052.2016-02-24 20:12:57, 656 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - ooo Using Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:12:57, 656 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==> Preparing: select * from userwhereid=? The 2016-02-24 20:12:57, 664 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - = = > the Parameters: 1 (Integer) id = 1, the age = 0, the userName = guowuxin, userAddress = Beijing. The 2016-02-24 20:12:57, 679 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ooo Using Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:12:57, 679 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==> Preparing: select * from userwhereid=? The 2016-02-24 20:12:57, 679 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - = = > the Parameters: Id = 2, 2 (Integer) age = 0, the userName = guoxiaoming, userAddress = Beijing. The 2016-02-24 20:12:57, 679 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Resetting autocommit totrueOn the JDBC Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:12:57, 679 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:12:57, 679 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Returned connection 3874052 to pool.Copy the code

The second level caching mechanism means that the same data content can be shared between different sessions.

import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Test; import com.guowuxin.mybatis.mapper.UserMapper; import com.guowuxin.mybatis.model.User; import junit.framework.TestCase; public class TestTwoCache extends TestCase{ public static SqlSessionFactory sqlSessionFactory; static{ String resource ="mybatis-config.xml";        try {            InputStream inputStream = Resources.getResourceAsStream(resource);            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);        } catch (IOException e) {            e.printStackTrace();        }    }    @Test     public void testCache() { SqlSession sqlSession1 = sqlSessionFactory.openSession(); SqlSession sqlSession2 = sqlSessionFactory.openSession(); try { UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class); User u1=mapper1.getUserById(1); System.out.println(u1); sqlSession1.commit(); UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User u2=mapper2.getUserById(1); System.out.println(u2); sqlSession2.commit(); } finally { sqlSession1.close(); sqlSession2.close(); }}}Copy the code

SQL statements are executed twice before level 2 caching is enabled.

The 2016-02-24 20:28:10, 786 main DEBUG (org. Apache. Ibatis. The datasource. Pooled. PooledDataSource) - PooledDataSource forcefully Closed/removed all connections. 2016-02-24 20:28:10, 850 main DEBUG (org. Apache. Ibatis. Transaction. JDBC. JdbcTransaction) - Openning JDBC Connection2016-02-24 20:28:11, 011 main DEBUG (org. Apache. Ibatis. The datasource. Pooled. PooledDataSource) - 24 20:28:11 Created connection - 3874052.2016-02, 012 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - ooo Using the Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:28:11, 013 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==> Preparing: select * from userwhereid=? The 2016-02-24 20:28:11, 030 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - = = > the Parameters: 1 (Integer) id = 1, the age = 0, the userName = guowuxin, userAddress = Beijing. The 2016-02-24 20:28:11, 040 main DEBUG (org. Apache. Ibatis. Transaction. JDBC. JdbcTransaction) - Openning JDBC Connection2016-02-24 20:28:11, 154 main DEBUG (org. Apache. Ibatis. The datasource. Pooled. PooledDataSource) - 29420695.2016-02-24 20:28:11 Created connection, 154 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ooo Using Connection [com. Mysql. JDBC JDBC4Connection @ 1 c0ec97] 2016-02-24 20:28:11, 154 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==> Preparing: select * from userwhereid=? The 2016-02-24 20:28:11, 154 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - = = > the Parameters: 1 (Integer) id = 1, the age = 0, the userName = guowuxin, userAddress = Beijing. The 2016-02-24 20:28:11, 154 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Resetting autocommit totrueOn the JDBC Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:28:11, 154 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com. Mysql. JDBC JDBC4Connection @ 3 b1d04] 2016-02-24 20:28:11, 154 main DEBUG (org. Apache. Ibatis. The datasource. Pooled. PooledDataSource) - Returned 3874052 to the connection pool. The 20:28:11 2016-02-24, 154 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Resetting autocommit totrueOn the JDBC Connection [com. Mysql. JDBC JDBC4Connection @ 1 c0ec97] 2016-02-24 20:28:11, 154 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com. Mysql. JDBC JDBC4Connection @ 1 c0ec97] 2016-02-24 20:28:11, 154 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Returned connection 29420695 to pool.------------------------Copy the code

Add <? To the entity class mapping file Encoding XML version = “1.0” = “utf-8”? >


<! DOCTYPE mapper PUBLIC"- / / mybatis.org//DTD Mapper / 3.0 / EN"    "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <! Namespace = PostsMapper interface = PostsMapper interface = PostsMapper interface = PostsMapper interface = PostsMapper interface = PostsMapper interface"com.guowuxin.mybatis.mapper.UserMapper"> <! <cache /> <select ID ="getUserById" parameterType="int" resultType="User">            select * from user where id=#{id} Copy the code
The 2016-02-25 10:15:11, 162 main DEBUG (org. Apache. Ibatis. The datasource. Pooled. PooledDataSource) - Created the connection 22522451.2016-02-25 10:15:11, 164 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - ooo Using Connection [com. Mysql. JDBC. JDBC4Connection @ 157 aa53] 2016-02-25 10:15:11, 164 main DEBUG (com.guowuxin.mybatis.mapper.UserMapper.getUserById) - ==> Preparing: select * from userwhereid=? The 2016-02-25 10:15:11, 182 main DEBUG (. Com. Guowuxin. Mybatis mapper. UserMapper. GetUserById) - = = > the Parameters: 1 (Integer) id = 1, the age = 0, the userName = guowuxin, userAddress = Beijing. The 2016-02-25 10:15:11, 196 main DEBUG (org.apache.ibatis.cache.decorators.LoggingCache) - Cache Hit Ratio [com.guowuxin.mybatis.mapper.UserMapper]: Id = 1, 0.5 the age = 0, the userName = guowuxin, userAddress = Beijing. The 2016-02-25 10:15:11, 196 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Resetting autocommit totrueOn the JDBC Connection [com. Mysql. JDBC JDBC4Connection @ 157 aa53] 2016-02-25 10:15:11, 196 main DEBUG (org.apache.ibatis.transaction.jdbc.JdbcTransaction) - Closing JDBC Connection [com. Mysql. JDBC. JDBC4Connection @ 157 aa53] 2016-02-25 10:15:11, 197 main DEBUG (org.apache.ibatis.datasource.pooled.PooledDataSource) - Returned connection 22522451 to pool.Copy the code

——————————————— if you want to implement a cache hit, you must commit the last sqlSession before it takes effect. Otherwise, the cache will not hit. Mybatis cache will be wrapped in a TransactionCache class. All cache.putObject will be temporarily stored in a map. The cache objects in this map will be putObject by the actual cache class. The purpose of this design is to prevent the rollback caused by an exception in the process of transaction execution. If the object is directly put into the cache, in case of rollback, it is easy to cause the myBatis cache to be dirty read


Refer to the article: http://my.oschina.net/KingPan/blog/280167#OSC_h1_1