mybatis的缓存机制及用例介绍
在实际的项目开发中,通常对数据库的查询性能要求很高,而mybatis提供了查询缓存来缓存数据,从而达到提高查询性能的要求。
mybatis的查询缓存分为一级缓存和二级缓存,一级缓存是SqlSession级别的缓存,二级缓存时mapper级别的缓存,二级缓存是多个SqlSession共享的。mybatis通过缓存机制减轻数据压力,提高数据库性能。
一级缓存:
mybatis的一级缓存是SQLSession级别的缓存,在操作数据库时需要构造SqlSession对象,在对象中有一个HashMap用于存储缓存数据,不同的SqlSession之间缓存数据区域(HashMap)是互相不影响的。
一级缓存的作用域是SqlSession范围的,当在同一个SqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存)中,第二次查询时会从缓存中获取数据,不再去底层进行数据库查询,从而提高了查询效率。需要注意的是:如果SqlSession执行了DML操作(insert、update、delete),并执行commit()操作,mybatis则会清空SqlSession中的一级缓存,这样做的目的是为了保证缓存数据中存储的是最新的信息,避免出现脏读现象。
当一个SqlSession结束后该SqlSession中的一级缓存也就不存在了,Mybatis默认开启一级缓存,不需要进行任何配置。
注意:Mybatis的缓存机制是基于id进行缓存,也就是说Mybatis在使用HashMap缓存数据时,是使用对象的id作为key,而对象作为value保存
例子说明:
工程架构图:
pom.xml
<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.gm.test</groupId>
<artifactId>MybatisCacheTest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- spring版本号 -->
<spring.version>4.3.10.RELEASE</spring.version>
<!-- mybatis版本号 -->
<mybatis.version>3.2.6</mybatis.version>
<!-- log4j日志文件管理包版本 -->
<slf4j.version>1.7.7</slf4j.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<!-- 表示开发的时候引入,发布的时候不会加载此包 -->
<scope>test</scope>
</dependency>
<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- aop -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
<!-- mybatis核心包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- mybatis/spring包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<!-- 导入java ee jar 包 -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
<!-- 导入Mysql数据库链接jar包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.30</version>
</dependency>
<!-- 导入dbcp的jar包,用来在applicationContext.xml中配置数据库 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<!-- JSTL标签类 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 日志文件管理包 -->
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<!-- 格式化对象,方便输出日志 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.41</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<version>3.1</version>
</configuration>
</plugin>
</plugins>
</build>
</project>
sql语句:
CREATE TABLE employee(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
loginname VARCHAR(18),
PASSWORD VARCHAR(18),
NAME VARCHAR(18) DEFAULT NULL,
sex CHAR(2) DEFAULT NULL,
age INT(11) DEFAULT NULL,
phone VARCHAR(21),
sal DOUBLE,
state VARCHAR(18)
);
INSERT INTO employee (loginname,PASSWORD,NAME,sex,age,phone,sal,state) VALUES('jack','123456','杰克','男',26,'12345678936',9800,'ACTIVE');
INSERT INTO employee (loginname,PASSWORD,NAME,sex,age,phone,sal,state) VALUES('rose','123456','露丝','女',21,'78965412395',6800,'ACTIVE');
INSERT INTO employee (loginname,PASSWORD,NAME,sex,age,phone,sal,state) VALUES('tom','123456','汤姆','男',25,'13902017777',8800,'ACTIVE');
INSERT INTO employee (loginname,PASSWORD,NAME,sex,age,phone,sal,state) VALUES('alice','123456','爱丽丝','女',20,'74185296375',5800,'ACTIVE');
log4j.properties:
log4j.rootLogger=ERROR, stdout
log4j.logger.com.gm.mapper.EmployeeMapper=DEBUG
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%-12d{HH\:mm\:ss.SS}] [%p] %l %m%n
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
mybatis-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>
<!-- 全局参数 -->
<settings>
<!-- 设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER,插入空值时不需要指定类型 -->
<setting name="jdbcTypeForNull" value="NULL" />
<!-- 要使延迟加载生效必须配置下面两个属性 -->
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyLoading" value="false" />
<setting name="logImpl" value="LOG4J" />
</settings>
<!-- <plugins> <plugin interceptor="com.manager.util.MybatisInterceptor"></plugin>
</plugins> -->
<environments default="mysql">
<environment id="mysql">
<!-- 指定事务管理类型,type="JDBC"指直接简单使用了JDBC的提交和回滚设置 -->
<transactionManager type="JDBC" />
<!-- dataSource指数据源配置,POOLED是JDBC连接对象的数据源连接池的实现 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="1qaz@wsx" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/gm/mapper/EmployeeMapper.xml" />
</mappers>
</configuration>
Employee.java:
package com.gm.domain;
import java.io.Serializable;
public class Employee implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer id;
private String loginname;
private String password;
private String name;
private String sex;
private String age;
private String phone;
private Double sal;
private String state;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLoginname() {
return loginname;
}
public void setLoginname(String loginname) {
this.loginname = loginname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
EmployeeMapper.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.gm.mapper.EmployeeMapper">
<select id="selectEmployeeById" parameterType="int"
resultType="com.gm.domain.Employee">
SELECT * FROM employee WHERE id = #{id}
</select>
<!-- 查询所有Employee -->
<select id="selectAllEmployee" parameterType="int"
resultType="com.gm.domain.Employee">
SELECT * FROM employee
</select>
<!-- 根据id删除Employee -->
<delete id="deleteEmployeeById" parameterType="int">
DELETE FROM
employee WHERE id = #{id}
</delete>
</mapper>
EmployeeMapper.java:
package com.gm.mapper;
import java.util.List;
import com.gm.domain.Employee;
public interface EmployeeMapper {
// 根据id查询Employee
Employee selectEmployeeById(Integer id);
// 查询所有Employee
List<Employee> selectAllEmployee();
// 根据id删除Employee
void deleteEmployeeById(Integer id);
}
工厂工具类:MySqlSessionFactory.java:
package com.gm.factory;
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;
public class MySqlSessionFactory {
private static SqlSessionFactory sqlSessionFactory = null;
static {
try {
InputStream inputStream = Resources
.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// 获取SqlSession对象的静态方法
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
// 获取SqlSessionFactory的静态方法
public static SqlSessionFactory getSessionFactory() {
return sqlSessionFactory;
}
}
执行方法类一:OneLevelCacheTest.java
package com.gm.test;
import org.apache.ibatis.session.SqlSession;
import com.gm.domain.Employee;
import com.gm.factory.MySqlSessionFactory;
import com.gm.mapper.EmployeeMapper;
public class OneLevelCacheTest {
public void testCache1() {
// 使用工厂类获得SqlSession对象
SqlSession sqlSession = MySqlSessionFactory.getSqlSession();
// 获得EmployeeMapping对象
EmployeeMapper employeeMapper = sqlSession
.getMapper(EmployeeMapper.class);
Employee employee1 = employeeMapper.selectEmployeeById(1);
System.out.println(employee1);
// 再次查询id为1的Employee对象,因为是同一个SqlSession,所以会从之前的一级缓存中查找数据
Employee employee2 = employeeMapper.selectEmployeeById(1);
System.out.println(employee2);
sqlSession.close();
}
public static void main(String[] args) {
OneLevelCacheTest t = new OneLevelCacheTest();
t.testCache1();
}
public void testCache2() {
// 使用工厂类获得SqlSession对象
SqlSession sqlSession = MySqlSessionFactory.getSqlSession();
// 获得EmployeeMapping对象
EmployeeMapper employeeMapper = sqlSession
.getMapper(EmployeeMapper.class);
Employee employee1 = employeeMapper.selectEmployeeById(1);
System.out.println(employee1);
// 执行delete操作
employeeMapper.deleteEmployeeById(4);
// commit提交
sqlSession.commit();
// 再次查询id为1的Employee对象,因为DML操作会清空sqlSession缓存,所以会再次执行select语句
Employee employee2 = employeeMapper.selectEmployeeById(1);
System.out.println(employee2);
sqlSession.close();
}
public void testCache3() {
// 使用工厂类获得SqlSession对象
SqlSession sqlSession = MySqlSessionFactory.getSqlSession();
// 获得EmployeeMapping对象
EmployeeMapper employeeMapper = sqlSession
.getMapper(EmployeeMapper.class);
Employee employee1 = employeeMapper.selectEmployeeById(1);
System.out.println(employee1);
// 关闭一级缓存
sqlSession.close();
// 再次访问,需要再次获取一级缓存,然后才能查找数据,否则会抛出异常
sqlSession = MySqlSessionFactory.getSqlSession();
// 再次获得EmployeeMapper对象
employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee2 = employeeMapper.selectEmployeeById(1);
System.out.println(employee2);
sqlSession.close();
}
public void testCache4() {
// 使用工厂类获得SqlSession对象
SqlSession sqlSession = MySqlSessionFactory.getSqlSession();
// 获得EmployeeMapping对象
EmployeeMapper employeeMapper = sqlSession
.getMapper(EmployeeMapper.class);
Employee employee1 = employeeMapper.selectEmployeeById(1);
System.out.println(employee1);
// 关闭一级缓存
sqlSession.close();
// 再次访问,需要再次获取一级缓存,然后才能查找数据,否则会抛出异常
sqlSession = MySqlSessionFactory.getSqlSession();
// 再次获得EmployeeMapper对象
employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
// 再次查询id为1的Employee对象,因为DML操作会清空sqlSession缓存,所以会再次执行select语句
Employee employee2 = employeeMapper.selectEmployeeById(1);
System.out.println(employee2);
sqlSession.close();
}
}
运行之后结果:
2018-08-22 09:35:47,858 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?
2018-08-22 09:35:47,886 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)
2018-08-22 09:35:47,899 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1
com.gm.domain.Employee@56235b8e
com.gm.domain.Employee@56235b8e
通过观察结果可以看出,在第一次查询id为1的Employee对象时执行了一条select语句,但是第二次获取id为1的Employee对象时并没有执行select语句,因为此时一级缓存也就是SqlSession缓存中已经缓存了id为1的Employee对象,Mybatis直接从缓存中将对象取出来,并没有再次去查询数据库,所以第二次也就没有执行select语句
执行方法类二:
public static void main(String[] args) {
OneLevelCacheTest t = new OneLevelCacheTest();
t.testCache2();
}
运行之后的结果:
2018-08-22 09:41:17,024 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?
2018-08-22 09:41:17,045 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)
2018-08-22 09:41:17,058 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1
com.gm.domain.Employee@56235b8e
2018-08-22 09:41:17,058 DEBUG [com.gm.mapper.EmployeeMapper.deleteEmployeeById] - ==> Preparing: DELETE FROM employee WHERE id = ?
2018-08-22 09:41:17,059 DEBUG [com.gm.mapper.EmployeeMapper.deleteEmployeeById] - ==> Parameters: 4(Integer)
2018-08-22 09:41:17,079 DEBUG [com.gm.mapper.EmployeeMapper.deleteEmployeeById] - <== Updates: 1
2018-08-22 09:41:17,125 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?
2018-08-22 09:41:17,125 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)
2018-08-22 09:41:17,128 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1
com.gm.domain.Employee@370736d9
结果分析:在第一次查询id为1的employee对象时执行了一条select语句,接下来执行了一个delete并commit操作,Mybatis为了保证缓存中存储的是最新消息,会清空SqlSession缓存。当第二次获取id为1的User对象时一级缓存也就是SqlSession缓存中并没有缓存任何对象,所以Mybatis再次执行语句去查询id为1的Exployee对象。
这里有兴趣的朋友可以试试delete操作之后不commit()操作,看Mybatis是否会再次执行查询语句。
执行方法类三:
public static void main(String[] args) {
OneLevelCacheTest t = new OneLevelCacheTest();
t.testCache3();
}
运行结果:
2018-08-22 09:45:03,482 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?
2018-08-22 09:45:03,505 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)
2018-08-22 09:45:03,518 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1
com.gm.domain.Employee@56235b8e
2018-08-22 09:45:03,520 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?
2018-08-22 09:45:03,520 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)
2018-08-22 09:45:03,523 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1
com.gm.domain.Employee@6d7b4f4c
结果分析:在第一次查询id为1的User对象时执行了一条select语句,接下来调用SqlSession的close()方法,该方法会关闭SqlSession缓存,当第二次获取id为1的Employee对象时一级缓存也就是SqlSession缓存是一个新的对象,其中并没有缓存任何对象,所以Mybatis再次执行select语句去查询id为1的Employee对象。
二级缓存:
二级缓存是mapper级别的缓存,使用二级缓存时,多个SqlSession使用同一个Mapper的sql语句去操作数据库,得到的数据会存在二级缓存区域,它同样是使用HashMapper进行数据存储,相比一级缓存SqlSession,二级缓存的范围更大,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的SqlSession两次执行相同的namespace下的sql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。
Mybatis默认没有开启二级缓存,需要在setting全局参数中配置开启二级缓存。
在mybatis-config.xml中配置:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
cacheEnabled的value为true表示在此配置文件下开启二级缓存,该属性默认为false。
在EmployeeMapper.xml中配置:
<!-- 开启当前mapper的namespace下的二级缓存 -->
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
以上配置创建了一个LRU缓存,并每隔60秒刷新,最大存储512个对象,而且返回的对象被认为是只读。
cache元素用来开启当前mapper的namespace下的二级缓存,该元素的属性设置如下:
- flushInterval:刷新间隔,可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段,默认情况下是不设置的,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
- size:缓存数目,可以被设置为任意正整数,要记住你的缓存对象数目和你运行环境可用内存资源数目,默认值是1024.
- readOnly:只读,属性可以被设置为true或false,只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改。这提供了很重要的性能优势,可读写的缓存会返回缓存对象的拷贝(通过序列化),这会慢一些,但是安全,因此默认是false。
- eviction:收回策略,默认为LRU,有如下几种:
- LRU:最近最少使用的策略,移除最长时间不被使用的对象。
- FIFO:先进先出策略,按对象进入缓存的顺序来移除它们。
- SOFT:软引用策略,移除基于垃圾回收器状态和软引用规则的对象。
- WEAK:弱引用策略,更积极地移除基于垃圾收集器状态和弱引用规则的对象。
注意:使用二级缓存时,与查询结果映射的java对象必须实现java.io.Serializable接口的序列化和反序列化操作,如果存在父类,其成员都需要实现序列化接口,实现序列化接口是为了对缓存数据进行序列化和反序列化操作,因为二级缓存数据存储介质多种多样,不一定在内存,有可能是硬盘或者远程服务器。
执行方法类四:
public static void main(String[] args) {
OneLevelCacheTest t = new OneLevelCacheTest();
t.testCache4();
}
运行结果:
2018-08-22 09:48:32,330 DEBUG [com.gm.mapper.EmployeeMapper] - Cache Hit Ratio [com.gm.mapper.EmployeeMapper]: 0.0
2018-08-22 09:48:32,523 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?
2018-08-22 09:48:32,544 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)
2018-08-22 09:48:32,558 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1
com.gm.domain.Employee@6f1fba17
2018-08-22 09:48:32,560 DEBUG [com.gm.mapper.EmployeeMapper] - Cache Hit Ratio [com.gm.mapper.EmployeeMapper]: 0.5
com.gm.domain.Employee@6f1fba17
若禁用当前select语句的二级缓存,修改EmployeeMapper.xml如下:
<select id="selectEmployeeById" parameterType="int" resultType="com.gm.domain.Employee" useCache="false">
此时运行结果:
2018-08-22 09:50:22,782 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?
2018-08-22 09:50:22,805 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)
2018-08-22 09:50:22,822 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1
com.gm.domain.Employee@6536e911
2018-08-22 09:50:22,824 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ?
2018-08-22 09:50:22,824 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer)
2018-08-22 09:50:22,828 DEBUG [com.gm.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1
com.gm.domain.Employee@6f1fba17
结果分析:第一次查询时,虽然关闭了SqlSession也就是一级缓存,但是因为启用了二级缓存,第一次查询到的结果被保存到二级缓存中,Mybatis在一级缓存中没有找到id为1的Employee对象,就会去二级缓存中查找,所以不会再次执行select语句。当禁用了二级缓存,又关闭了SqlSession,第二次查询mybatis就会再一次执行一次select语句。
修改EmployeeMapper.xml如下:
<!-- 根据id删除Employee -->
<delete id="deleteEmployeeById" parameterType="int" flushCache="true" useCache="false">
DELETE FROM
employee WHERE id = #{id}
</delete>
在select语句时,如果没有去配置flushCache、useCache,
flushCache默认为false,表示任何时候语句被调用,都不会去清空本地缓存和二级缓存。
useCache默认为true,表示会将本条语句的结果进行二级缓存。在insert、update、delete语句时, flushCache默认为true,表示任何时候语句被调用,都会导致本地缓存和二级缓存被清空。 useCache属性在该情况下没有。update 的时候如果 flushCache="false",则当你更新后,查询的数据数据还是老的数据。
小结:本文介绍了Mybatis的缓存机制,包括一级缓存SqlSession和二级缓存mapper,使用缓存可以最大程度低减轻数据查询压力,提高数据库性能。
mybatis的缓存机制及用例介绍的更多相关文章
- 深入浅出mybatis之缓存机制
目录 前言 准备工作 MyBatis默认缓存设置 缓存实现原理分析 参数localCacheScope控制的缓存策略 参数cacheEnabled控制的缓存策略 总结 前言 提到缓存,我们都会不约而同 ...
- mybatis(四)缓存机制
转载:https://www.cnblogs.com/wuzhenzhao/p/11103043.html 缓存是一般的ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力.跟Hibe ...
- MyBatis - 5.缓存机制
MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制.缓存可以极大的提升查询效率. MyBatis系统中默认定义了两级缓存. 一级缓存和二级缓存. 1.默认情况下,只有一级缓存( ...
- MyBatis 的缓存机制
缓存机制可以减轻数据库的压力,原理是在第一查询时,将查询结果缓存起来,之后再查询同样的sql, 不是真的去查询数据库,而是直接返回缓存中的结果. 缓存可以降低数据库的压力,但同时可能无法得到最新的结果 ...
- MyBatis框架——缓存机制
使⽤缓存机制的作⽤也是减少 Java 应⽤程序与数据库的交互次数,从⽽提升程序的运⾏效率. ⽐如第 ⼀次查询出某个对象之后,MyBatis 会⾃动将其存⼊缓存,当下⼀次查询同⼀个对象时,就可以直接从 ...
- mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache
1.1 什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 s ...
- 【Redis缓存机制】1.Redis介绍和使用场景
(1)持久化数据库的缺点平常我们使用的关系型数据库有Mysql.Oracle以及SqlServer等,在开发的过程中,数据通常都是通过Web提供的数据库驱动来链接数据库进行增删改查. 那么,我们日常使 ...
- mybatis的缓存机制
一级缓存: MyBatis的一级缓存指的是在一个Session域内,session为关闭的时候执行的查询会根据SQL为key被缓存(跟mysql缓存一样,修改任何参数的值都会导致缓存失效) packa ...
- 聊聊MyBatis缓存机制【美团-推荐】
聊聊MyBatis缓存机制 2018年01月19日 作者: 凯伦 文章链接 18778字 38分钟阅读 前言 MyBatis是常见的Java数据库访问层框架.在日常工作中,开发人员多数情况下是使用My ...
随机推荐
- 二、小程序内嵌Html基础格式说明
1.index.js文件更改 var WxParse = require('../../wxParse/wxParse.js'); Page({ data: { }, onLoad: function ...
- iView的Message提示框
全局配置message main.js Vue.prototype.$Message.config({ top: 70, duration:3 }); Vue.prototype.$Message.c ...
- bzoj1495 [NOI2006]网络收费 复杂度分析+树上背包
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=1495 题解 通过观察可以发现,对于一个 \(lca\),如果 \(nA \leq nB\),那 ...
- python 的set定义
set是集合,跟数学中的集合一样不能重复没有顺序 set定义有两种方式 1. b=set([1, 2, 3, 4]) 2. a={"} 输出: b=set([1, 2, 3, 4])a={1 ...
- linux清理缓存
在free -h中查看自己的内存发现在运行一段时间后,有很多内存都被缓存占用, 所以要清理下缓存,增大可用内存 直接进入root账户,输入以下命令 echo 3 > /proc/sys/vm/d ...
- springboot 操作redis
redis五大类型用法 Redis五大类型:字符串(String).哈希/散列/字典(Hash).列表(List).集合(Set).有序集合(sorted set)五种Controller:@Reso ...
- Ubuntu查找软件命令
查找软件: apt-cache search <your search item>
- mobx学习笔记02——mobx基础语法(class)
新的语法可能不被浏览器支持,可以使用babel转换为浏览器支持的代码格式: 为什么要定义class? js是一门面向对象的编程语言.需要利用类来复用代码,提高编程效率. 需要什么样的class能力? ...
- 报数问题:有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位
n = int(input("请输入人数:")) list_p = list(range(1,n+1)) #将所有人放在一个数字里面 count = 0 #设置一个变量,用户计算报 ...
- struts2---访问WEB
一:在Action中,可以通过以下方式访问WEB的HttpSession,HttpServletRequest,HttpServletResponse等资源 与Servlet API解耦的访问方式 通 ...