在实际的项目开发中,通常对数据库的查询性能要求很高,而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的缓存机制及用例介绍的更多相关文章

  1. 深入浅出mybatis之缓存机制

    目录 前言 准备工作 MyBatis默认缓存设置 缓存实现原理分析 参数localCacheScope控制的缓存策略 参数cacheEnabled控制的缓存策略 总结 前言 提到缓存,我们都会不约而同 ...

  2. mybatis(四)缓存机制

    转载:https://www.cnblogs.com/wuzhenzhao/p/11103043.html 缓存是一般的ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力.跟Hibe ...

  3. MyBatis - 5.缓存机制

    MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制.缓存可以极大的提升查询效率. MyBatis系统中默认定义了两级缓存. 一级缓存和二级缓存. 1.默认情况下,只有一级缓存( ...

  4. MyBatis 的缓存机制

    缓存机制可以减轻数据库的压力,原理是在第一查询时,将查询结果缓存起来,之后再查询同样的sql, 不是真的去查询数据库,而是直接返回缓存中的结果. 缓存可以降低数据库的压力,但同时可能无法得到最新的结果 ...

  5. MyBatis框架——缓存机制

    使⽤缓存机制的作⽤也是减少 Java 应⽤程序与数据库的交互次数,从⽽提升程序的运⾏效率. ⽐如第 ⼀次查询出某个对象之后,MyBatis 会⾃动将其存⼊缓存,当下⼀次查询同⼀个对象时,就可以直接从 ...

  6. mybatis的缓存机制(一级缓存二级缓存和刷新缓存)和mybatis整合ehcache

    1.1  什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 一级缓存是SqlSession级别的缓存.在操作数据库时需要构造 s ...

  7. 【Redis缓存机制】1.Redis介绍和使用场景

    (1)持久化数据库的缺点平常我们使用的关系型数据库有Mysql.Oracle以及SqlServer等,在开发的过程中,数据通常都是通过Web提供的数据库驱动来链接数据库进行增删改查. 那么,我们日常使 ...

  8. mybatis的缓存机制

    一级缓存: MyBatis的一级缓存指的是在一个Session域内,session为关闭的时候执行的查询会根据SQL为key被缓存(跟mysql缓存一样,修改任何参数的值都会导致缓存失效) packa ...

  9. 聊聊MyBatis缓存机制【美团-推荐】

    聊聊MyBatis缓存机制 2018年01月19日 作者: 凯伦 文章链接 18778字 38分钟阅读 前言 MyBatis是常见的Java数据库访问层框架.在日常工作中,开发人员多数情况下是使用My ...

随机推荐

  1. vue,一路走来(16)--本地及手机调试

    闲暇时间记录一下如何绑定域名,实现本地及手机调试的过程.我的是微信开发项目,很多功能及操作都是基于微信来开发的,理所当然的就用到微信开发者工具了. 1.首先打开目录C:\Windows\System3 ...

  2. 一、dynamic

    一.dynamic使用: 从一直使用动态类型写接口 返回动态类型出现情况 1.返回接口每次不知道包含那些列(实体类解决) 2.操作的数据类型 不可知(参与数值计算-实体类解决明确类型) Dynamic ...

  3. Java疯狂讲义笔记——内部类

    [定义]内部类:定义在其它类内部的类.外部类:包含内部类的类,也称 宿主类.局部内部类:定义在方法里的内部类. [接口内部类]接口中也可以定义内部类,必须为public static修饰(自动添加), ...

  4. CSS Reset(样式重置)

    CSS Reset,意为重置默认样式.HTML中绝大部分标签元素在网页显示中都有一个默认属性值,通常为了避免重复定义元素样式,需要进行重置默认样式(CSS Reset).举几个例子:1.淘宝(CSS ...

  5. golang对象

    对象和组合 package main import ( "fmt" ) type father struct { name string sex int } type sun st ...

  6. SpringBoot---概述

    1.概述 1.1.SpringBoot解决什么问题? 1.1.1.配置---> 自动化配置 1.1.2.依赖---> SpringBoot提供了一系列的Start POM,整合各项功能的时 ...

  7. Halo(六)

    Spring publish-event 机制 监听者模式包含了一个监听者 Listener 与之对应的事件 Event,还有一个事件发布者 EventPublish. 过程就是 EventPubli ...

  8. boost Shared Memory

    Shared Memory Shared memory is typically the fastest form of interprocess communicatioin. It provide ...

  9. python环境变量

    下载并升级更新pip python -m pip install -U pip 变量名:PY_HOME   变量值:python路径 path:win10加在最后(记得用;号隔开):win7加在前面记 ...

  10. paper 155:face/head pose estimation

    参考来源:http://www.cnblogs.com/lanye/p/5312620.html 人脸姿态估计:pitch,yaw,roll三种角度,分别代表上下翻转,左右翻转,平面内旋转的角度.   ...