五、mybatis两级缓存

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

  •  一级缓存是一直开启的。
  •   与数据库同一次会话期间查询到的数据会放在本地缓存中。
  •   以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查数据库。

验证实例(实时使用上一篇的目录结构):

接口文件EmployeeMapper.java:

Employee getEmpById(int id);

映射文件EmployeeMapper.xml

1 <select id="getEmpById" parameterType="Integer" resultType="entity.Employee">
2         select LAST_NAME AS
3         lastName,gender as gender,email as email from
4         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 exception
17         } 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("男");
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 exception
39         } finally {
40             if (openSession != null) {
41                 openSession.close();
42             }
43 
44         }
45     }

运行结果:如图:

 

 

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

 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 AS
26         lastName,gender as gender,email as email from
27         tbl_employee where id =#{asdsdfsdf}
28     </select>
29 
30 </mapper>

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

 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     @Override
58     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 exception
23         } 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 AS
3         lastName,gender as gender,email as email from
4         tbl_employee where id =#{asdsdfsdf}
5     </select>

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

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

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

 

posted @ 2022-03-04 22:18  啄木鸟伍迪  阅读(81)  评论(0编辑  收藏  举报
//火箭 GenerateContentList();