Mybatis的缓存机制
2018-07-30 09:34
435 查看
在实际的项目开发中,通常对数据库的查询性能要求很高,而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保存
例子说明:
sql语句:
log4j.properties:
mybatis-config.xml:
Employee.java:
EmployeeMapper.xml:
EmployeeMapper.java:
工厂工具类:ZSqlSessionFactory.java:
执行方法类一:OneLevelCacheTest.java
运行之后结果:
通过观察结果可以看出,在第一次查询id为1的Employee对象时执行了一条select语句,但是第二次获取id为1的Employee对象时并没有执行select语句,因为此时一级缓存也就是SqlSession缓存中已经缓存了id为1的Employee对象,Mybatis直接从缓存中将对象取出来,并没有再次去查询数据库,所以第二次也就没有执行select语句
执行方法类二:
运行之后的结果:
结果分析:在第一次查询id为1的employee对象时执行了一条select语句,接下来执行了一个delete并commit操作,Mybatis为了保证缓存中存储的是最新消息,会清空SqlSession缓存。当第二次获取id为1的User对象时一级缓存也就是SqlSession缓存中并没有缓存任何对象,所以Mybatis再次执行语句去查询id为1的Exployee对象。
这里有兴趣的朋友可以试试delete操作之后不commit()操作,看Mybatis是否会再次执行查询语句。
执行方法类三:
运行结果:
结果分析:在第一次查询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中配置:
cacheEnabled的value为true表示在此配置文件下开启二级缓存,该属性默认为false。
在EmployeeMapper.xml中配置:
以上配置创建了一个LRU缓存,并每隔60秒刷新,最大存储512个对象,而且返回的对象被认为是只读。
cache元素用来开启当前mapper的namespace下的二级缓存,该元素的属性设置如下:
flushInterval:刷新间隔,可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段,默认情况下是不设置的,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size:缓存数目,可以被设置为任意正整数,要记住你的缓存对象数目和你运行环境可用内存资源数目,默认值是1024.
readOnly:只读,属性可以被设置为true或false,只读的缓存会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改。这提供了很重要的性能优势,可读写的缓存会返回缓存对象的拷贝(通过序列化),这会慢一些,但是安全,因此默认是false。
eviction:收回策略,默认为LRU,有如下几种:
LRU:最近最少使用的策略,移除最长时间不被使用的对象。
FIFO:先进先出策略,按对象进入缓存的顺序来移除它们。
SOFT:软引用策略,移除基于垃圾回收器状态和软引用规则的对象。
WEAK:弱引用策略,更积极地移除基于垃圾收集器状态和弱引用规则的对象。
注意:使用二级缓存时,与查询结果映射的java对象必须实现java.io.Serializable接口的序列化和反序列化操作,如果存在父类,其成员都需要实现序列化接口,实现序列化接口是为了对缓存数据进行序列化和反序列化操作,因为二级缓存数据存储介质多种多样,不一定在内存,有可能是硬盘或者远程服务器。
执行方法类四:
运行结果:
若禁用当前select语句的二级缓存,修改EmployeeMapper.xml如下:
此时运行结果:
结果分析:第一次查询时,虽然关闭了SqlSession也就是一级缓存,但是因为启用了二级缓存,第一次查询到的结果被保存到二级缓存中,Mybatis在一级缓存中没有找到id为1的Employee对象,就会去二级缓存中查找,所以不会再次执行select语句。当禁用了二级缓存,又关闭了SqlSession,第二次查询mybatis就会再一次执行一次select语句。
小结:本文介绍了Mybatis的缓存机制,包括一级缓存SqlSession和二级缓存mapper,使用缓存可以最大程度低减轻数据查询压力,提高数据库性能。
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保存
例子说明:
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.zxc.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> <!-- mappers 告诉了Mybatis去哪里找持久化类的映射文件 --> <settings> <!-- 要使延迟加载生效必须配置下面两个属性 --> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> <setting name="logImpl" value="LOG4J" /> </settings> <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="sfhq1866"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/zxc/mapper/EmployeeMapper.xml"/> </mappers> </configuration>
Employee.java:
package com.zxc.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.zxc.mapper.EmployeeMapper"> <select id="selectEmployeeById" parameterType="int" resultType="com.zxc.domain.Employee"> SELECT * FROM employee WHERE id = #{id} </select> <!-- 查询所有Employee --> <select id="selectAllEmployee" parameterType="int" resultType="com.zxc.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.zxc.mapper; import java.util.List; import com.zxc.domain.Employee; public interface EmployeeMapper { //根据id查询Employee Employee selectEmployeeById(Integer id); //查询所有Employee List<Employee> selectAllEmployee(); //根据id删除Employee void deleteEmployeeById(Integer id); }
工厂工具类:ZSqlSessionFactory.java:
package com.zxc.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 ZSqlSessionFactory { 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.zxc.test; import org.apache.ibatis.session.SqlSession; import com.zxc.domain.Employee; import com.zxc.factory.ZSqlSessionFactory; import com.zxc.mapper.EmployeeMapper; public class OneLevelCacheTest { public void testCache1(){ //使用工厂类获得SqlSession对象 SqlSession sqlSession = ZSqlSessionFactory.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(); } }
运行之后结果:
2017-04-01 18:07:21,577 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ? 2017-04-01 18:07:21,637 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer) 2017-04-01 18:07:21,720 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1 com.zxc.domain.Employee@6a33ee9b com.zxc.domain.Employee@6a33ee9b
通过观察结果可以看出,在第一次查询id为1的Employee对象时执行了一条select语句,但是第二次获取id为1的Employee对象时并没有执行select语句,因为此时一级缓存也就是SqlSession缓存中已经缓存了id为1的Employee对象,Mybatis直接从缓存中将对象取出来,并没有再次去查询数据库,所以第二次也就没有执行select语句
执行方法类二:
public void testCache1(){ //使用工厂类获得SqlSession对象 SqlSession sqlSession = ZSqlSessionFactory.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(); }
运行之后的结果:
10:06:52.691 [main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.log4j2.Log4j2Impl' adapter. 2017-04-05 10:06:53,129 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ? 2017-04-05 10:06:53,186 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer) 2017-04-05 10:06:53,215 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1 com.zxc.domain.Employee@6a33ee9b 2017-04-05 10:06:53,216 DEBUG [com.zxc.mapper.EmployeeMapper.deleteEmployeeById] - ==> Preparing: DELETE FROM employee WHERE id = ? 2017-04-05 10:06:53,216 DEBUG [com.zxc.mapper.EmployeeMapper.deleteEmployeeById] - ==> Parameters: 4(Integer) 2017-04-05 10:06:53,217 DEBUG [com.zxc.mapper.EmployeeMapper.deleteEmployeeById] - <== Updates: 1 2017-04-05 10:06:53,219 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ? 2017-04-05 10:06:53,219 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer) 2017-04-05 10:06:53,221 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1 com.zxc.domain.Employee@1e2fce9c
结果分析:在第一次查询id为1的employee对象时执行了一条select语句,接下来执行了一个delete并commit操作,Mybatis为了保证缓存中存储的是最新消息,会清空SqlSession缓存。当第二次获取id为1的User对象时一级缓存也就是SqlSession缓存中并没有缓存任何对象,所以Mybatis再次执行语句去查询id为1的Exployee对象。
这里有兴趣的朋友可以试试delete操作之后不commit()操作,看Mybatis是否会再次执行查询语句。
执行方法类三:
public void testCache1(){ //使用工厂类获得SqlSession对象 SqlSession sqlSession = ZSqlSessionFactory.getSqlSession(); //获得EmployeeMapping对象 EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class); Employee employee1 = employeeMapper.selectEmployeeById(1); System.out.println(employee1); //关闭一级缓存 sqlSession.close(); //再次访问,需要再次获取一级缓存,然后才能查找数据,否则会抛出异常 sqlSession = ZSqlSessionFactory.getSqlSession(); //再次获得EmployeeMapper对象 employeeMapper = sqlSession.getMapper(EmployeeMapper.class); Employee employee2 = employeeMapper.selectEmployeeById(1); System.out.println(employee2); sqlSession.close(); }
运行结果:
17:12:03.705 [main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.log4j2.Log4j2Impl' adapter. 2017-04-05 17:12:04,151 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ? 2017-04-05 17:12:04,204 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer) 2017-04-05 17:12:04,230 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1 com.zxc.domain.Employee@3016f5a0 2017-04-05 17:12:04,231 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ? 2017-04-05 17:12:04,231 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer) 2017-04-05 17:12:04,233 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1 com.zxc.domain.Employee@77763895
结果分析:在第一次查询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 void testCache1(){ //使用工厂类获得SqlSession对象 SqlSession sqlSession = ZSqlSessionFactory.getSqlSession(); //获得EmployeeMapping对象 EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class); Employee employee1 = employeeMapper.selectEmployeeById(1); System.out.println(employee1); //关闭一级缓存 sqlSession.close(); //再次访问,需要再次获取一级缓存,然后才能查找数据,否则会抛出异常 sqlSession = ZSqlSessionFactory.getSqlSession(); //再次获得EmployeeMapper对象 employeeMapper = sqlSession.getMapper(EmployeeMapper.class); //再次查询id为1的Employee对象,因为DML操作会清空sqlSession缓存,所以会再次执行select语句 Employee employee2 = employeeMapper.selectEmployeeById(1); System.out.println(employee2); sqlSession.close(); }
运行结果:
18:18:10.743 [main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.log4j2.Log4j2Impl' adapter. 2017-04-05 18:18:10,920 DEBUG [com.zxc.mapper.EmployeeMapper] - Cache Hit Ratio [com.zxc.mapper.EmployeeMapper]: 0.0 2017-04-05 18:18:11,169 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ? 2017-04-05 18:18:11,224 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer) 2017-04-05 18:18:11,252 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1 com.zxc.domain.Employee@2934ad41 2017-04-05 18:18:11,254 DEBUG [com.zxc.mapper.EmployeeMapper] - Cache Hit Ratio [com.zxc.mapper.EmployeeMapper]: 0.5 com.zxc.domain.Employee@2934ad41
若禁用当前select语句的二级缓存,修改EmployeeMapper.xml如下:
<select id="selectEmployeeById" parameterType="int" resultType="com.zxc.domain.Employee" useCache="false">
此时运行结果:
18:20:30.418 [main] DEBUG org.apache.ibatis.logging.LogFactory - Logging initialized using 'class org.apache.ibatis.logging.log4j2.Log4j2Impl' adapter. 2017-04-05 18:20:30,861 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ? 2017-04-05 18:20:30,916 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer) 2017-04-05 18:20:30,943 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1 com.zxc.domain.Employee@54d5da26 2017-04-05 18:20:30,945 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Preparing: SELECT * FROM employee WHERE id = ? 2017-04-05 18:20:30,945 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - ==> Parameters: 1(Integer) 2017-04-05 18:20:30,947 DEBUG [com.zxc.mapper.EmployeeMapper.selectEmployeeById] - <== Total: 1 com.zxc.domain.Employee@7116778b
结果分析:第一次查询时,虽然关闭了SqlSession也就是一级缓存,但是因为启用了二级缓存,第一次查询到的结果被保存到二级缓存中,Mybatis在一级缓存中没有找到id为1的Employee对象,就会去二级缓存中查找,所以不会再次执行select语句。当禁用了二级缓存,又关闭了SqlSession,第二次查询mybatis就会再一次执行一次select语句。
小结:本文介绍了Mybatis的缓存机制,包括一级缓存SqlSession和二级缓存mapper,使用缓存可以最大程度低减轻数据查询压力,提高数据库性能。
相关文章推荐
- 《深入理解mybatis原理》 MyBatis缓存机制的设计与实现
- 《深入理解mybatis原理》 MyBatis缓存机制的设计与实现
- MyBatis 3(6)缓存机制
- 我对MyBatis的缓存机制的理解
- MyBatis 缓存机制
- mybatis缓存机制
- Mybatis缓存机制
- SSM 之《深入理解mybatis原理》 MyBatis缓存机制的设计与实现
- 关于MyBatis的缓存机制
- MyBatis 缓存机制深度解剖 / 自定义二级缓存
- 《深入理解mybatis原理》 MyBatis缓存机制的设计与实现
- MyBatis 缓存机制深度解剖 / 自定义二级缓存
- Mybatis缓存机制
- java互联网架构-Mybatis缓存机制
- mybatis缓存机制详解(一)——Cache
- Mybatis源码学习(四)一级缓存机制
- mybatis缓存机制
- 聊聊MyBatis缓存机制
- MyBatis缓存机制
- Mybatis缓存机制