五mybatis两级缓存
Posted 啄木鸟伍迪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了五mybatis两级缓存相关的知识,希望对你有一定的参考价值。
一级缓存:(本地缓存) sqlSession级别的缓存。
- 一级缓存是一直开启的。
- 与数据库同一次会话期间查询到的数据会放在本地缓存中。
- 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查数据库。
验证实例(实时使用上一篇的目录结构):
接口文件EmployeeMapper.java:
Employee getEmpById(int id);
映射文件EmployeeMapper.xml
<select id="getEmpById" parameterType="Integer" resultType="entity.Employee"> select LAST_NAME AS lastName,gender as gender,email as email from tbl_employee where id =#asdsdfsdf </select>
junit测试类:
@Test public void test02() String resource = "mybatis-config.xml"; SqlSession openSession = null; try InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 获取openSession 不会自动提交数据 openSession = sqlSessionFactory.openSession(true); EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = mapper.getEmpById(1); Employee employee1 = mapper.getEmpById(1); System.out.println("测试一级缓存:" + employee); System.out.println("测试一级缓存:" + employee1 + "," + (employee == employee1)); catch (Exception e) // TODO: handle exception finally if (openSession != null) openSession.close();
运行结果:
测试一级缓存:Employee [id=null, lastName=joy33333, email=joy52112225@iclound.com, gender=女]
测试一级缓存:Employee [id=null, lastName=joy33333, email=joy52112225@iclound.com, gender=女],true
运行结果说明:
employee ==employee1 结果为true说明两个地址值相同,说明是同一个employee;
控制台日志显示查询的SQL语句只执行了一次,说明SQL只执行了一次;
一级缓存失效的情况(没有使用到当前一级缓存的情况:效果就是,还需要像数据库发请求)
1.只要sqlSession不同
2.sqlSession相同,查询条件不同;原因是当前一级缓存中还没有该数据;
3.sqlSession相同,两次查询中执行了 增删改 操作也会失效;原因是增删改操作可能会影响数据。
4.qlSession相同 但是手动清空了一级缓存
验证实例(实时使用上一篇的目录结构):
接口文件EmployeeMapper.java:
同上
映射文件EmployeeMapper.xml
同上
junit测试类:
@Test public void test02() String resource = "mybatis-config.xml"; SqlSession openSession = null; SqlSession openSession2 = null; try InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 获取openSession 不会自动提交数据 openSession = sqlSessionFactory.openSession(true); openSession2 = sqlSessionFactory.openSession(true); EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = mapper.getEmpById(1); Employee employee1 = mapper.getEmpById(1); System.out.println("测试一级缓存:" + employee); System.out.println("测试一级缓存:" + employee1 + "," + (employee == employee1)); EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class); Employee employee2 = mapper2.getEmpById(1); System.out.println("sqlSession改变 一级缓存失效:" + employee2 + "," + (employee1 == employee2)); EmployeeMapper mapper23 = openSession2.getMapper(EmployeeMapper.class); Employee employee23 = mapper23.getEmpById(2); System.out.println("查询条件改变改变 一级缓存失效:" + employee23 + "," + (employee1 == employee23)); Employee emp = new Employee(); emp.setLastName("Tom"); emp.setGender("男"); emp.setEmail("678@qq.com"); mapper23.addEmp(emp); Employee employee4 = mapper23.getEmpById(2); System.out.println("查询条件相同+sqlSession相同 一级缓存失效:" + employee23 + "," + (employee4 == employee23)); Employee employee5 = mapper23.getEmpById(2); openSession2.clearCache(); Employee employee6 = mapper23.getEmpById(2); System.out.println("手动清楚缓存:" + (employee5 == employee6)); catch (Exception e) // TODO: handle exception finally if (openSession != null) openSession.close();
运行结果:如图:
二级缓存:(全局缓存) 基于namespace级别的一个缓存:
一个namespace对应一个二级缓存;
工作机制:
1.一个会话,查询一条数据,这个数据会被放在一级缓存中;
2.如果会话关闭,一级缓存中的数据会被保存到二级缓存中;新会话查询信息,就可以参照二级缓存中的内容
3.sqlSession EmployeeMapper Employee DepartmentMapper Department
不同namespace查出的数据会放在自己对应的缓存(map)中
效果,数据会从二级缓存中取,查出的数据都会放在一级缓存中; 只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中;
使用步骤:
1.开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/>
2.去mapper.xml中配置使用二级缓存;
3.我们的POJO需要实现序列化接口;
验证实例(实时使用上一篇的目录结构):
全局文件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> <properties resource="dbconfig.properties"></properties> <settings> <setting name="cacheEnabled" value="true" /> </settings> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="$jdbc.driver" /> <property name="url" value="$jdbc.url" /> <property name="username" value="$jdbc.username" /> <property name="password" value="$jdbc.password" /> </dataSource> </environment> <environment id="development_mysql2"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="$jdbc2.driver" /> <property name="url" value="$jdbc2.url" /> <property name="username" value="$jdbc2.username" /> <property name="password" value="$jdbc2.password" /> </dataSource> </environment> </environments> <databaseIdProvider type="DB_VENDOR"> <!-- 为不同的数据库厂商取别名 --> <property name="MySQL" value="mysql" /> <property name="Oracle" value="oracle" /> <property name="SQL Server" value="sqlserver" /> </databaseIdProvider> <mappers> <package name="dao" /> </mappers> </configuration>
映射文件EmployeeMapper.xml:使用二级缓存<cache></cache>
cache 标签的属性说明:
- eviction:缓存回收策略;
- flushInterval:缓存刷新间隔,多长时间清空一次,默认不清空
- readOnly:缓存只读;true: mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据;
- mybatis为了加快速度,直接把数据在缓存中的引用交给用户;不安全;
- false:非只读;mybatis局的数据可能会被修改。mybatis会利用序列化和反序列化的技术克隆一份新数据给用户;安全,速度慢
- size:存放多少元素;
- type:指定自定义缓存的全类名;实现cache接口即可;
<?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="dao.EmployeeMapper"> <cache></cache> <insert id="addEmp" parameterType="entity.Employee" useGeneratedKeys="true" keyProperty="id"> insert into tbl_employee(last_name,gender,email) values( #lastName,#gender,#email ) </insert> <select id="getEmpById" parameterType="Integer" resultType="entity.Employee"> select LAST_NAME AS lastName,gender as gender,email as email from tbl_employee where id =#asdsdfsdf </select> </mapper>
Employee.java实体类实现序列化接口:
package entity; import java.io.Serializable; public class Employee implements Serializable /** * */ private static final long serialVersionUID = -6962919367201266002L; private Integer id; private String lastName; private String email; private String gender; private Department department; public Integer getId() return id; public void setId(Integer id) this.id = id; public String getLastName() return lastName; public void setLastName(String lastName) this.lastName = lastName; public String getEmail() return email; public void setEmail(String email) this.email = email; public String getGender() return gender; public void setGender(String gender) this.gender = gender; public Department getDepartment() return department; public void setDepartment(Department department) this.department = department; @Override public String toString() return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]";
接口文件EmployeeMapper.java:
void addEmp(Employee employee); Employee getEmpById(int id);
junit测试类:
@Test public void test01() String resource = "mybatis-config.xml"; SqlSession openSession = null; SqlSession openSession2 = null; try InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 获取openSession 不会自动提交数据 openSession = sqlSessionFactory.openSession(true); openSession2 = sqlSessionFactory.openSession(true); EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class); Employee employee = mapper.getEmpById(1); System.out.println("测试二级缓存:" + employee); openSession.close(); Employee employee1 = mapper2.getEmpById(1); System.out.println("测试二级缓存:" + employee1); openSession2.close(); catch (Exception e) // TODO: handle exception finally if (openSession != null) openSession.close(); openSession2.close();
运行结果:
运行结果说明:
Cache Hit Ratio [dao.EmployeeMapper]: 0.5 且没有 发送相同的SQL,说明 :第二次的记录是从缓存Cache Hit Ratio
中取出的;
和缓存有关的设置和属性:
1.cacheEnabled = true; false会关闭二级缓存;不会关闭一级缓存
2.每个select 都有 useCache="true" 若为false 关闭的是二级缓存一级缓存没有关闭
3. 每个增删标签的:flushCache="true" 增删改操作执行完成后就清除缓存 一级缓存失效;二级缓存也会失效
每个select 都有 flushCache="false" 若为true 一级缓存失效;二级缓存也会失效
即:
<select id="getEmpById" parameterType="Integer" resultType="entity.Employee" flushCache="true"> select LAST_NAME AS lastName,gender as gender,email as email from tbl_employee where id =#asdsdfsdf </select>
运行结果如下图:发送了两次sql;一级缓存失效;二级缓存也会失效;
4. openSession2.clearCache(); 是清空的是一级缓存,不会影响二级缓存
5.localCacheScope:本地缓存作用域(一级缓存session 当前会话的所有数据保存在会话中) statement可以禁用一级缓存
以上是关于五mybatis两级缓存的主要内容,如果未能解决你的问题,请参考以下文章