一级缓存和二级缓存
其他章节及开发包:https://blog.youkuaiyun.com/XIMAX/article/details/106255196
环境 :Eclipse+Tomcat9+JDK10+Mybatis-3.1.1、Navicat
一级缓存
-
一级缓存默认是开启的
-
一级缓存存储作用域为 Session,当 Session flush 或 close 之后,该Session中的所有 Cache 就将清空。
-
一级缓存是SqlSession级别的缓存,缓存数据存储在HashMap中,在进行第一次查询时,首先会从数据库中查询出结果,然后将结果存在一级缓存中;当我们第二次查询时,首先会查询一级缓存,如果一级缓存没有,再查询数据库。在进行CUD操作并执行了commit或关闭Sqlsession后会将缓存清空。
-----------------------------------------------------------分割线----------------------------------------------------------------
一级缓存较为简单,不做代码赘述,看一个简单案例
@Test
void test() throws IOException {
SqlSessionFactory factory = MybatisUtils.getFactory();
SqlSession session = factory.openSession();
String statement = "com.rjxy.test7.userMapper.getUser";
CUser user = session.selectOne(statement,1);
System.out.println(user);
user = session.selectOne(statement,1);
System.out.println(user);
System.out.println("--------------");
//清理掉则不会用一级缓存
session.clearCache();
user = session.selectOne(statement,1);
System.out.println(user);
System.out.println("---------------");
//关闭后再打开,不是同一session对象,不会用一级缓存
session.close();
session = factory.openSession();
user = session.selectOne(statement,1);
System.out.println(user);
session.close();
}
结果输出:
2020-05-21 12:25:00,968 [main] DEBUG [com.rjxy.test7.userMapper.getUser] - ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@4fbda97b]
2020-05-21 12:25:00,969 [main] DEBUG [com.rjxy.test7.userMapper.getUser] - ==> Preparing: select * from c_user where id=?
2020-05-21 12:25:01,031 [main] DEBUG [com.rjxy.test7.userMapper.getUser] - ==> Parameters: 1(Integer)
CUser [id=1, name=Tom, age=12]
CUser [id=1, name=Tom, age=12]
--------------
2020-05-21 12:25:01,163 [main] DEBUG [com.rjxy.test7.userMapper.getUser] - ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@4fbda97b]
2020-05-21 12:25:01,163 [main] DEBUG [com.rjxy.test7.userMapper.getUser] - ==> Preparing: select * from c_user where id=?
2020-05-21 12:25:01,163 [main] DEBUG [com.rjxy.test7.userMapper.getUser] - ==> Parameters: 1(Integer)
CUser [id=1, name=Tom, age=12]
---------------
2020-05-21 12:25:01,167 [main] DEBUG [com.rjxy.test7.userMapper.getUser] - ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@4fbda97b]
2020-05-21 12:25:01,167 [main] DEBUG [com.rjxy.test7.userMapper.getUser] - ==> Preparing: select * from c_user where id=?
2020-05-21 12:25:01,168 [main] DEBUG [com.rjxy.test7.userMapper.getUser] - ==> Parameters: 1(Integer)
CUser [id=1, name=Tom, age=12]
从结果中可以看出第一部分中,当同一session第二次查询相同内容时,没有再调用sql语句,而是直接从缓存中取出,清理掉缓存及关闭session再打开查询时又重新调用了sql语句,无法共享
二级缓存
- 二级缓存存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache
- 二级缓存是Mapper级别的缓存,拥有多个SqlSession,同一Mapper中每个SqlSession中的缓存内容共享。若要使用二级缓存则存储数据的Java类需要实现Serializable接口。
- 在进行CUD操作并执行了commit,缓存会被清空,默认不开启,开启需要在配置文件userMapper.xml中设置“”
test1~8分别对应八章,本章使用包test8、tool,文件config.xml、db.properties、log4j.properties
代码
建库,建表
CREATE TABLE c_user(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
age INT
);
INSERT INTO c_user(NAME, age) VALUES('Tom', 12);
INSERT INTO c_user(NAME, age) VALUES('Jack', 11);
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>
<properties resource="db.properties"></properties>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<typeAliases>
<package name="com.rjxy.test8"/>
<typeAliases>
<typeAliases>
<package name="com.rjxy.test2"/>
<typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/rjxy/test8/userMapper.xml"/>
<mappers>
</configuration>
userMapper8.xml
<?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.rjxy.test8.userMapper8">
<cache></cache>
<select id="getUser" parameterType="int" resultType="CUser2">
select * from c_user where id=#{id}
</select>
<update id="updateUser" parameterType="CUser2">
update c_user set name=#{name},age=#{age} where id=#{id}
</update>
</mapper>
CUser2.java
package com.rjxy.test8;
import java.io.Serializable;
public class CUser2 implements Serializable{
private static final long serialVersionUID = 1L;
//二级缓存需要实现序列化接口
private int id;
private String name;
private int age;
public CUser2() {}
public CUser2(int id,String name,int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "CUser [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
JTest8.java
package com.rjxy.test8;
import java.io.IOException;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.jupiter.api.Test;
class JTest8 {
@Test
void test2() throws IOException {
SqlSessionFactory factory = MybatisUtils.getFactory();
SqlSession session1 = factory.openSession();
SqlSession session2 = factory.openSession();
String statement = "com.rjxy.test8.userMapper8.getUser";
CUser2 user = session1.selectOne(statement,1);
session1.commit();
System.out.println(user);
CUser2 user2 = session2.selectOne(statement,1);
session2.commit();
System.out.println(user2);
}
}
其它
其它文件与该系列第一篇相同 链接: https://blog.youkuaiyun.com/XIMAX/article/details/106244701
输出结果
2020-05-21 13:14:02,992 [main] DEBUG [com.rjxy.test8.userMapper8.getUser] - ooo Using Connection [com.mysql.cj.jdbc.ConnectionImpl@4fbda97b]
2020-05-21 13:14:02,993 [main] DEBUG [com.rjxy.test8.userMapper8.getUser] - ==> Preparing: select * from c_user where id=?
2020-05-21 13:14:03,098 [main] DEBUG [com.rjxy.test8.userMapper8.getUser] - ==> Parameters: 1(Integer)
CUser [id=1, name=Tom, age=12]
CUser [id=1, name=Tom, age=12]
可以看出,第二次查询与第一次查询所用的是同一个mapper文件下不同的session,但第二次查询没有调用sql语句