mybatis缓存的简单理解和使用
mybatis缓存数据的介绍
缓存是存在于内存中的临时数据,使用缓存的目的是减少和数据库的数据进行交互的次数,提高执行效率。像很多持久化框架一样,Mybatis也提供了缓存策略,通过缓存策略来减少数据库的查询次数,从而提高性能,Mybatis中缓存分为一级缓存和二级缓存。
创建maven模块项目:
准备配置文件:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.etime</groupId>
<artifactId>day12</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
config.xml
编写核心配置文件,将setting 配置日志logImpl…到properties和typeAliases之间
<?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="jdbc.properties"></properties>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.etime.pojo"/>
</typeAliases>
<!-- 配置 mybatis的环境-->
<environments default="development">
<!-- 配置环境-->
<environment id="development">
<!-- 配置事物类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的信息:用的是数据源[连接池]-->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<!-- jdbc:mysql://localhost:3306/db_school?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC-->
<!-- 和javaWeb servlet三层架构中的区别这里是只需要设置时区就可以了
jdbc:mysql://localhost:3306/db_school?serverTimezone=UTC-->
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 注册StudentDao接口映射文件位置-->
<mappers>
<package name="com.etime.mapper"/>
</mappers>
</configuration>
jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_418?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=h123456
SqlSessionUtil.java
package com.etime.util;
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 java.io.IOException;
import java.io.InputStream;
public class SqlSessionUtil {
private static SqlSession sqlSession =null;
static {
//加载配置文件
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream("config.xml");
} catch (IOException e) {
e.printStackTrace();
}
//用于读取配置文件内容,生成SqlSessionFactory
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
//获取SqlSession对象
//参数为true,则底层调用setAutoCommit方法时,
sqlSession = sqlSessionFactory.openSession(true);
}
public SqlSession getSqlSession(){
return sqlSession;
}
}
一级缓存
mybatis一级缓存一种是session级别的,针对同一个会话SqlSession中,执行多次条件完全相同一个sql,那么会共享这一缓存。
其特点是它是自带的,不能卸载,通过SqlSession级别的缓存,使用无需配置。
Student.java
package com.etime.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Student {
private int sid;
private String sname;
private int cid;
}
StudentMapper.java
package com.etime.mapper;
import com.etime.pojo.Student;
import java.util.List;
public interface StudentMapper {
List<Student> getAllStudent();
}
编写学生持久层映射文件StudentMapper.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.etime.mapper.StudentMapper">
<!-- resultType="stu"-->
<select id="getAllStudent" resultType="Student">
select * from student
</select>
</mapper>
编写测试方法:
package com.etime.demo;
import com.etime.mapper.StudentMapper;
import com.etime.pojo.Student;
import com.etime.util.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class MybatisTest {
SqlSessionUtil sqlSessionUtil =new SqlSessionUtil();
@Test
public void t01(){
SqlSession sqlSession = sqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> list = studentMapper.getAllStudent();
list.forEach(System.out::println);
System.out.println("---------------------------------");
List<Student> list1 = studentMapper.getAllStudent();
list1.forEach(System.out::println);
}
}
运行结果:
一级缓存的分析总结
从以上的测试结果来看我们是通过两次查询的方式,只有第一次是在一级缓存中没有数据,是因为session是新创建的,所以第一次的数据是实实在在从数据库中查询出来的。然后会接着让数据放入到一级缓存中去的,此时要注意的是,一级缓存是一个Map集合,map的key是你的查询条件字符串,值就是查询出来的对象。到第二次查询的时候,就是直接到一级缓存中将数据取出的。这样大大减少了和数据的一次交互,提高了执行效率。
二级缓存
二级缓存:默认条件下是不开启的使用时需要进行配置
二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
配置:通过设置cacheEnable设置二级缓存开启
<!-- 开启二级缓存-->
<setting name="cacheEnabled" value="true"/>
配置statement上面的useCache属性,当useCache设置为true时需要使用二级缓存。如果不适用二级缓存可以设置false
注意的是:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存
<mapper namespace="com.etime.mapper.StudentMapper">
<!-- 需要配置cache -->
<cache></cache>
<!-- resultType="stu"-->
<select id="getAllStudent" resultType="Student" useCache="true">
select * from student
</select>
</mapper>
实体类需要序列化
package com.etime.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Student implements Serializable {
private int sid;
private String sname;
private int cid;
}
测试:需要清理缓存,使用commit提交了数据只是把一级缓存清理,可以在二级缓存 中拿到数据,如果使用clearCache时是直接把一级和二级缓存都清理了,所以在从二级缓存中查找数据时就没办法查找到数据
@Test
public void t02(){
SqlSession sqlSession = sqlSessionUtil.getSqlSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
List<Student> list = studentMapper.getAllStudent();
list.forEach(System.out::println);
//清理缓存
//使用commit提交了数据只是把一级缓存清理,可以在二级缓存中拿取到数据
sqlSession.commit();
// 使用clearCache是直接把一级和二级缓存都清理了,所以二级缓存就找不到数据
//sqlSession.clearCache();
System.out.println("---------------------------------");
List<Student> list1 = studentMapper.getAllStudent();
list1.forEach(System.out::println);
sqlSession.close();
}
运行结果: