一、缓存简介
什么是缓存
- 存在内存中的临时数据
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库的数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题
为什么使用缓存
-
什么样的数据能使用缓存
-
MyBatis缓存
MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大地提升查询效率
- Mybatis系统中默认定义了两级缓存:一级缓存和二级缓存
use mybatis;
create table user ( id int(20) not null primary key, name varchar(30) default null, pwd varchar(30) default null )engine=innodb charset=utf-8;
insert into user (id, name, pwd) values (1, ‘comprehensive’, ‘123456’), (2, ‘何光伦’, ‘234567’), (3, ‘焦锦彪’, ‘345678’), (4, ‘李杰亮’, ‘456789’), (5, ‘周希程’, ‘56789’);
```xml
<!-- Maven项目的xml文件——导入依赖 -->
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/comprehensive.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
<?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">
<!-- UserMapper.xml映射器文件 -->
<mapper namespace="com.comprehensive.dao.UserMapper">
<select id="getUsers" resultType="com.comprehensive.pojo.User">
select * from mybatis.user
</select>
<select id="getUserById" parameterType="_int" resultType="com.comprehensive.pojo.User">
select * from mybatis.user where id=#{id}
</select>
<update id="updateUserById" parameterType="map">
update mybatis.user
<set>
<if test="name != null">
name=#{name},
</if>
<if test="pwd != null">
pwd=#{pwd}
</if>
</set>
where id=#{id}
</update>
</mapper>
<?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>
<!-- mybatis-config.xml文件——配置日志实现 -->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&characterSetResults=utf-8&useSSL=false&verifyServerCertificate=false&autoReconnect=true&autoReconnectForPools=true&allowMultiQueries=true"/>
<property name="username" value="root"/>
<property name="password" value="txq199807031578"/>
</dataSource>
</environment>
</environments>
<!-- 每一个mapper.xml都需要在MyBatis核心配置文件中注册 -->
<mappers>
<mapper resource="com/comprehensive/dao/UserMapper.xml"/>
</mappers>
</configuration>
//User实体类
public class User {
private int id;
private String name;
private String pwd;
public User() {}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
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 String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
//UserMapper接口
public interface UserMapper {
List<User> getUsers();
User getUserById(int id);
void updateUserById(int id);
}
二、一级缓存
一级缓存测试
public class Test_cache {
@Test
public void test_cacheLevelOne() {
SqlSession sqlSession = MyBatis_Util.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.getUserById(1);
System.out.println("user1: " + user1);
System.out.println("================此处为分割线=================");
User user2 = mapper.getUserById(1);
System.out.println("user2: " + user2);
System.out.println("user1 == user2 ? " + user1.equals(user2));
sqlSession.close();
}
}
一级缓存失效的情况
一级缓存中不存在本次查询的对象
public class Test_cache { @Test public void test_cacheLevelOne() { SqlSession sqlSession = MyBatis_Util.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user1 = mapper.getUserById(1); System.out.println("user1: " + user1); System.out.println("================此处为分割线================="); User user2 = mapper.getUserById(2); System.out.println("user2: " + user2); System.out.println("user1 == user2 ? " + user1.equals(user2)); sqlSession.close(); } }
一级缓存刷新
三、二级缓存
具体的可以参照官方文档
二级缓存工作机制
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
- 如果当前会话关闭,这个会话对应的一级缓存就会消失;但是,会话关闭时,一级缓存中的数据会被保存到二级缓存中
- 新的会话查询信息,就可以从二级缓存中获取内容
不同的mapper映射器文件查询出来的数据会放在它对应的二级缓存中
二级缓存测试
开启全局缓存
<?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>
<!-- mybatis-config.xml文件——配置日志实现 -->
<settings>
<setting name="logImpl" value="LOG4J"/>
<setting name="cacheEnabled" value="true"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&characterSetResults=utf-8&useSSL=false&verifyServerCertificate=false&autoReconnect=true&autoReconnectForPools=true&allowMultiQueries=true"/>
<property name="username" value="root"/>
<property name="password" value="txq199807031578"/>
</dataSource>
</environment>
</environments>
<!-- 每一个mapper.xml都需要在MyBatis核心配置文件中注册 -->
<mappers>
<mapper resource="com/comprehensive/dao/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"> <!-- UserMapper.xml映射器文件 --> <mapper namespace="com.comprehensive.dao.UserMapper"> <!-- 在当前映射器文件中,使用二级缓存 --> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> <select id="getUsers" resultType="com.comprehensive.pojo.User"> select * from mybatis.user </select> <select id="getUserById" parameterType="_int" resultType="com.comprehensive.pojo.User"> select * from mybatis.user where id=#{id} </select> <update id="updateUserById" parameterType="map"> update mybatis.user <set> <if test="name != null"> name=#{name}, </if> <if test="pwd != null"> pwd=#{pwd} </if> </set> where id=#{id} </update> </mapper>
开始测试
public class Test_cache { @Test public void test_cacheLevelTwo() { SqlSession sqlSession1 = MyBatis_Util.getSqlSession(); UserMapper mapper = sqlSession1.getMapper(UserMapper.class); User user1 = mapper.getUserById(1); sqlSession1.close(); System.out.println("====第一次会话关闭,第二次会话开启===="); SqlSession sqlSession2 = MyBatis_Util.getSqlSession(); UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class); User user2 = mapper2.getUserById(1); sqlSession2.close(); System.out.println("user1 == user2 ? " + user1.equals(user2)); } }
四、MyBatis缓存原理