The cache is an area in the memory where data is stored. The purpose is to improve query efficiency. MyBatis will store the query results in the cache. When executes the same SQL next time, it will not access the database, but directly obtain the results from the cache, thus reducing the pressure on the server.
What is cache?
A piece of data that exists in memory.
What is the role of cache?
Reduce the interaction between the program and the database, improve query efficiency, and reduce the pressure on the server and database.
What kind of data is cached?
Data that is frequently queried but not frequently changed, and has little impact on the results after changes.
What are the categories of MyBatis cache?
Level 1 Cache and Level 2 Cache
How to determine whether two SQLs are the same?
The Sql statement of the query is the same, the parameter values passed are the same, the requirements for the result set are the same, the precompiled template ID is the same
MyBatis The first-level cache is also called local cache. The SqlSession object contains an Executor object, and the Executor object contains a PerpetualCache object, which stores first-level cache data.
Since the first-level cache is in the SqlSession object, the first-level cache can only be shared when using the same SqlSession object to operate the database.
MyBatis's first-level cache is enabled by default and does not require any configuration.
As shown below:
In fact, the test method is very simple, that is, by using the same and different SqlSession objects to perform SQL queries, you can know whether the hash values of the returned objects are the same. If the hash values returned are the same, it means that the SQL query is not performed, but directly Get the object from the cache to return
The following is using the same Session object to execute the query. If the hash values of user1 and user2 are the same, it means that the first level cache is indeed enabled, and There is no query, but the data is taken directly from the cache.
import com.mybatisstudy.mapper.UserMapper; import com.mybatisstudy.pojo.User; 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 java.io.InputStream; public class TestUserMapper3 { // 测试使用同一个SqlSession查询 @Test public void testCache1() throws Exception{ InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); // 使用同一个SqlSession查询 UserMapper mapper1 = session.getMapper(UserMapper.class); UserMapper mapper2 = session.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1.hashCode()); System.out.println("------------------------------------------"); User user2 = mapper2.findById(1); System.out.println(user2.hashCode()); session.close(); } }
Execution result
## OK, indeed the returned hash values are the same, and We can show through the console output that it does not query but directly gets the object from the cache and returns it, so this is the first-level cache, which improves query efficiency. Under different sqlsessions for testing, whether the returned hash value is consistent// 测试使用不同SqlSession查询 @Test public void testCache2() throws Exception{ InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session1 = factory.openSession(); SqlSession session2 = factory.openSession(); // 测试使用不同SqlSession查询 UserMapper mapper1 = session1.getMapper(UserMapper.class); UserMapper mapper2 = session2.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1.hashCode()); System.out.println("---------------------------------"); User user2 = mapper2.findById(1); System.out.println(user2.hashCode()); session1.close(); session2.close(); }Copy after login
OK, you can see that the returned hash value is different, and the output display of the console can also be seen that it is also a query here. The first-level cache is indeed based on the SqlSession objectBut, if there is too much cache, it will also affect us Query efficiency, so you need to clear the cache at this time, just like we have to clear the mobile phone cache from time to time otherwise it will be very stuck. It is the same reason. So how to clear the first-level cache?(2) Clear the first-level cache
Perform the following operations to clear the MyBatis first-level cache:Execution effectSqlSession calls close(): The SqlSession object is unavailable after the operation, and the object's Cached data is also unavailable.
- SqlSession calls clearCache() / commit(): The operation will clear the first-level cache data.
- SqlSession calls the addition, deletion and modification method: the operation will clear the first-level cache data, because the database changes after addition, deletion and modification, the cached data will be inaccurate
// 清空Mybatis一级缓存 @Test public void testCache3() throws Exception{ InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); UserMapper mapper1 = session.getMapper(UserMapper.class); UserMapper mapper2 = session.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1.hashCode()); // 清空Mybatis一级缓存 session.clearCache(); System.out.println("-------------------------------"); User user2 = mapper2.findById(1); System.out.println(user2.hashCode()); session.close(); }Copy after login
OK, the returned hash value is indeed different, but have we observed this? When using different SqlSession objects to execute queries above, the console input display is a bit different, that is, there is no need to establish a JDBC connection here, which also effectively improves query efficiency, so we still have to clear the cache occasionally
MyBatis二级缓存也叫全局缓存。数据存放在SqlSessionFactory中,只要是同一个工厂对象创建的SqlSession,在进行查询时都能共享数据。一般在项目中只有一个SqlSessionFactory对象,所以二级缓存的数据是全项目共享的。
MyBatis一级缓存存放的是对象,二级缓存存放的是对象的数据。所以要求二级缓存存放的POJO必须是可序列化的,也就是要实现Serializable接口。
MyBatis二级缓存默认不开启,手动开启后数据先存放在一级缓存中,只有一级缓存数据清空后,数据才会存到二级缓存中。
SqlSession 调用 clearCache() 无法将数据存到二级缓存中。
1. POJO类实现Serializable接口
import java.io.Serializable; public class User implements Serializable { private int id; private String username; private String sex; private String address; }
2. 在Mybatis配置文件添加如下设置
<!-- 二级缓存打开 --> <settings> <setting name="cacheEnabled" value="true"/> </settings>Copy after login
这里有个额外知识,就是Mybatis配置文件的标签还得按照顺序来放的,否则就会以下编译错误;
The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,
objectWrapperFactory?,reflectorFactory?,plugins?,environments?,
databaseIdProvider?,mappers?)".
同时也说明了放置顺序就得按照match里面的顺序来放
3. 添加
如果查询到的集合中对象过多,二级缓存只能缓存1024个对象引用。可以通过
标签的size属性修改该数量。 比如:
那怎么测试呢,从上面我们可以知道二级缓存存放的是对象的数据,并且是基于SqlSessionFactory的,因此我们可以用SqlSessionFactory获取两个SqlSession对象,然后让他们分别获取各自的mapper,然后进行查询,返回到同一个实例化的USer对象中,如果返回的数据是一致的,但是对象的哈希值是不一样的话,则说明二级缓存里存放的确实对象的数据而不是对象。
// 测试二级缓存 @Test public void testCache4() throws Exception { InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); SqlSession session = factory.openSession(); UserMapper mapper1 = session.getMapper(UserMapper.class); UserMapper mapper2 = session.getMapper(UserMapper.class); User user1 = mapper1.findById(1); System.out.println(user1); System.out.println(user1.hashCode()); // 让一级缓存失效 session.commit(); System.out.println("----------------------------"); user1 = mapper2.findById(1); System.out.println(user1); System.out.println(user1.hashCode()); }
运行结果
OK,从运行结果上我们可以知道结果集返回到同一个对象中,而他们的哈希值反而不一样,说明执行第二次查询的时候新建了一个对象并且该对象指向那个对象并且将SqlSessionFactory中的数据赋值到新建的那个对象。其实从控制台打印的日志我们也可以得出,并没有执行查询方法,因为没有打印SQL语句,而且缓存也是从0.0改成了0.5,因此我们可以断定二级缓存存放的是数据而不是对象。
The above is the detailed content of What are Java Mybatis first-level cache and second-level cache?. For more information, please follow other related articles on the PHP Chinese website!