五、mybatis两级缓存

  一级缓存:(本地缓存) sqlSession级别的缓存。

  •  一级缓存是一直开启的。
  •   与数据库同一次会话期间查询到的数据会放在本地缓存中。
  •   以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查数据库。
验证实例(实时使用上一篇的目录结构):

接口文件EmployeeMapper.java:

Employee getEmpById(int id);

映射文件EmployeeMapper.xml

1 <select id="getEmpById" parameterType="Integer" resultType="entity.Employee">2         select LAST_NAME AS3         lastName,gender as gender,email as email from4         tbl_employee where id =#{asdsdfsdf}5     </select>

junit测试类:

 1 @Test 2     public void test02() { 3         String resource = "mybatis-config.xml"; 4         SqlSession openSession = null; 5         try { 6             InputStream inputStream = Resources.getResourceAsStream(resource); 7             SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 8             // 获取openSession 不会自动提交数据 9             openSession = sqlSessionFactory.openSession(true);10             EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);11             Employee employee = mapper.getEmpById(1);12             Employee employee1 = mapper.getEmpById(1);13             System.out.println("测试一级缓存:" + employee);14             System.out.println("测试一级缓存:" + employee1 + "," + (employee == employee1));15         } catch (Exception e) {16             // TODO: handle exception17         } finally {18             if (openSession != null) {19                 openSession.close();20             }21 22         }23     }

运行结果:

测试一级缓存: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测试类:

 1 @Test 2     public void test02() { 3         String resource = "mybatis-config.xml"; 4         SqlSession openSession = null; 5         SqlSession openSession2 = null; 6         try { 7             InputStream inputStream = Resources.getResourceAsStream(resource); 8             SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 9             // 获取openSession 不会自动提交数据10             openSession = sqlSessionFactory.openSession(true);11             openSession2 = sqlSessionFactory.openSession(true);12             EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);13             Employee employee = mapper.getEmpById(1);14             Employee employee1 = mapper.getEmpById(1);15             System.out.println("测试一级缓存:" + employee);16             System.out.println("测试一级缓存:" + employee1 + "," + (employee == employee1));17 18             EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);19             Employee employee2 = mapper2.getEmpById(1);20             System.out.println("sqlSession改变 一级缓存失效:" + employee2 + "," + (employee1 == employee2));21             EmployeeMapper mapper23 = openSession2.getMapper(EmployeeMapper.class);22             Employee employee23 = mapper23.getEmpById(2);23             System.out.println("查询条件改变改变 一级缓存失效:" + employee23 + "," + (employee1 == employee23));24 25             Employee emp = new Employee();26             emp.setLastName("Tom");27             emp.setGender("男") 浙江党性培训 www.nxganxun.cn ;28             emp.setEmail("678@qq.com");29             mapper23.addEmp(emp);30             Employee employee4 = mapper23.getEmpById(2);31             System.out.println("查询条件相同+sqlSession相同 一级缓存失效:" + employee23 + "," + (employee4 == employee23));32 33             Employee employee5 = mapper23.getEmpById(2);34             openSession2.clearCache();35             Employee employee6 = mapper23.getEmpById(2);36             System.out.println("手动清楚缓存:" + (employee5 == employee6));37         } catch (Exception e) {38             // TODO: handle exception39         } finally {40             if (openSession != null) {41                 openSession.close();42             }43 44         }45     }

运行结果:如图:

997501-20220304121918508-2031939143.png

 

 

  二级缓存:(全局缓存) 基于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

ContractedBlock.gif ExpandedBlockStart.gif
 1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE configuration 3   PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4   "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 <configuration> 6     <properties resource="dbconfig.properties"></properties> 7  8     <settings> 9         <setting name="cacheEnabled" value="true" />10     </settings>11 12     <environments default="development">13         <environment id="development">14             <transactionManager type="JDBC" />15             <dataSource type="POOLED">16                 <property name="driver" value="${jdbc.driver}" />17                 <property name="url" value="${jdbc.url}" />18                 <property name="username" value="${jdbc.username}" />19                 <property name="password" value="${jdbc.password}" />20             </dataSource>21         </environment>22         <environment id="development_mysql2">23             <transactionManager type="JDBC" />24             <dataSource type="POOLED">25                 <property name="driver" value="${jdbc2.driver}" />26                 <property name="url" value="${jdbc2.url}" />27                 <property name="username" value="${jdbc2.username}" />28                 <property name="password" value="${jdbc2.password}" />29             </dataSource>30         </environment>31     </environments>32 33     <databaseIdProvider type="DB_VENDOR">34         <!-- 为不同的数据库厂商取别名 -->35         <property name="MySQL" value="mysql" />36         <property name="Oracle" value="oracle" />37         <property name="SQL Server" value="sqlserver" />38     </databaseIdProvider>39     <mappers>40         <package name="dao" />41     </mappers>42 </configuration>
View Code

映射文件EmployeeMapper.xml:使用二级缓存<cache></cache>

cache 标签的属性说明:

  • eviction:缓存回收策略;
  • flushInterval:缓存刷新间隔,多长时间清空一次,默认不清空
  • readOnly:缓存只读;true: mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据;
  • mybatis为了加快速度,直接把数据在缓存中的引用交给用户;不安全;
  • false:非只读;mybatis局的数据可能会被修改。mybatis会利用序列化和反序列化的技术克隆一份新数据给用户;安全,速度慢
  • size:存放多少元素;
  • type:指定自定义缓存的全类名;实现cache接口即可;
 1 <?xml version="1.0" encoding="UTF-8" ?> 2 <!DOCTYPE mapper 3   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4   "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="dao.EmployeeMapper"> 6 <cache></cache>18     <insert id="addEmp" parameterType="entity.Employee" useGeneratedKeys="true" keyProperty="id">19         insert into tbl_employee(last_name,gender,email) values(20         #{lastName},#{gender},#{email}21         )22     </insert>23     24     <select id="getEmpById" parameterType="Integer" resultType="entity.Employee">25         select LAST_NAME AS26         lastName,gender as gender,email as email from27         tbl_employee where id =#{asdsdfsdf}28     </select>29 30 </mapper>

Employee.java实体类实现序列化接口:

ContractedBlock.gif ExpandedBlockStart.gif
 1 package entity; 2  3 import java.io.Serializable; 4  5 public class Employee implements Serializable { 6  7     /** 8      *  9      */10     private static final long serialVersionUID = -6962919367201266002L;11     private Integer id;12     private String lastName;13     private String email;14     private String gender;15     private Department department;16 17     public Integer getId() {18         return id;19     }20 21     public void setId(Integer id) {22         this.id = id;23     }24 25     public String getLastName() {26         return lastName;27     }28 29     public void setLastName(String lastName) {30         this.lastName = lastName;31     }32 33     public String getEmail() {34         return email;35     }36 37     public void setEmail(String email) {38         this.email = email;39     }40 41     public String getGender() {42         return gender;43     }44 45     public void setGender(String gender) {46         this.gender = gender;47     }48 49     public Department getDepartment() {50         return department;51     }52 53     public void setDepartment(Department department) {54         this.department = department;55     }56 57     @Override58     public String toString() {59         return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]";60     }61 62 }
View Code

接口文件EmployeeMapper.java:

1 void addEmp(Employee employee);2     Employee getEmpById(int id);

junit测试类:

 

 1 @Test 2     public void test01() { 3         String resource = "mybatis-config.xml"; 4         SqlSession openSession = null; 5         SqlSession openSession2 = null; 6         try { 7             InputStream inputStream = Resources.getResourceAsStream(resource); 8             SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 9             // 获取openSession 不会自动提交数据10             openSession = sqlSessionFactory.openSession(true);11             openSession2 = sqlSessionFactory.openSession(true);12             EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);13             EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);14             Employee employee = mapper.getEmpById(1);15 16             System.out.println("测试二级缓存:" + employee);17             openSession.close();18             Employee employee1 = mapper2.getEmpById(1);19             System.out.println("测试二级缓存:" + employee1);20             openSession2.close();21         } catch (Exception e) {22             // TODO: handle exception23         } finally {24             if (openSession != null) {25                 openSession.close();26                 openSession2.close();27             }28 29         }30     }

运行结果:

运行结果说明:

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 一级缓存失效;二级缓存也会失效

即:

1 <select id="getEmpById" parameterType="Integer" resultType="entity.Employee" flushCache="true">2         select LAST_NAME AS3         lastName,gender as gender,email as email from4         tbl_employee where id =#{asdsdfsdf}5     </select>

运行结果如下图:发送了两次sql;一级缓存失效;二级缓存也会失效;

  4. openSession2.clearCache(); 是清空的是一级缓存,不会影响二级缓存

  5.localCacheScope:本地缓存作用域(一级缓存session 当前会话的所有数据保存在会话中) statement可以禁用一级缓存

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值