一级缓存和二级缓存
mybatis 测试实例:
- package com.atguigu.mybatis.test;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import org.apache.ibatis.io.Resources;
- import org.apache.ibatis.session.SqlSession;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.apache.ibatis.session.SqlSessionFactoryBuilder;
- import org.junit.Test;
- import com.atguigu.mybatis.bean.Department;
- import com.atguigu.mybatis.bean.Employee;
- import com.atguigu.mybatis.dao.DepartmentMapper;
- import com.atguigu.mybatis.dao.EmployeeMapper;
- import com.atguigu.mybatis.dao.EmployeeMapperAnnotation;
- import com.atguigu.mybatis.dao.EmployeeMapperDynamicSQL;
- import com.atguigu.mybatis.dao.EmployeeMapperPlus;
- public class MyBatisTest {
- public SqlSessionFactory getSqlSessionFactory() throws IOException {
- String resource = "mybatis-config.xml";
- InputStream inputStream = Resources.getResourceAsStream(resource);
- return new SqlSessionFactoryBuilder().build(inputStream);
- }
- /**
- * 两级缓存:
- * 一级缓存:(本地缓存):sqlSession 级别的缓存. 一级缓存是一直开启的; SqlSession 级别的一个 Mapper
- * 与数据库同一次会话期间查询到的数据会放在本地缓存中.
- * 以后如果需要获取相同的数据, 直接从缓存中拿, 没必要再去查询数据库;
- *
- * 一级缓存失效情况(没有使用到当前一级缓存的情况, 效果就是, 还需要再向数据库发出查询):
- * 1,sqlSession 不同.
- * 2,sqlSession 相同, 查询条件不同.(当前一级缓存中还没有这个数据)
- * 3,sqlSession 相同, 两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
- * 4,sqlSession 相同, 手动清除了一级缓存(缓存清空)
- *
- * 二级缓存:(全局缓存): 基于 namespace 级别的缓存: 一个 namespace 对应一个二级缓存:
- * 工作机制:
- * 1, 一个会话, 查询一条数据, 这个数据就会被放在当前会话的一级缓存中;
- * 2, 如果会话关闭; 一级缓存中的数据会被保存到二级缓存中; 新的会话查询信息, 就可以参照二级缓存中的内容;
- * 3,sqlSession===EmployeeMapper==>Employee
- * DepartmentMapper===>Department
- * 不同 namespace 查出的数据会放在自己对应的缓存中(map)
- * 效果: 数据会从二级缓存中获取
- * 查出的数据都会被默认先放在一级缓存中.
- * 只有会话提交或者关闭以后, 一级缓存中的数据才会转移到二级缓存中
- * 使用:
- * 1), 开启全局二级缓存配置:<setting name="cacheEnabled" value="true"/>
- * 2), 去 mapper.xml 中配置使用二级缓存:
- * <cache></cache>
- * 3), 我们的 POJO 需要实现序列化接口
- *
- * 和缓存有关的设置 / 属性:
- * 1),cacheEnabled=true:false: 关闭缓存(二级缓存关闭)(一级缓存一直可用的)
- * 2), 每个 select 标签都有 useCache="true":
- * false: 不使用缓存(一级缓存依然使用, 二级缓存不使用)
- * 3),[每个增删改查标签的: flushCache 标签的: flushCache="true":(一级二级都会清除), 这就是为啥执行增删改后一级缓存被清空了, 查询标签默认是 false]
- * 增删改执行完成后就会清楚缓存;
- * 测试: flushCache="true": 一级缓存就清空了; 二级也会被清除;
- * 查询标签: flushCache="false":
- * 如果 flushCache=true; 每次查询之后都会清空缓存; 缓存是没有被使用的;
- * 4),sqlSession.clearCache(); 只是清楚当前 session 的一级缓存;
- * 5),localCacheScope: 本地缓存作用域:(一级缓存 SESSION); 当前会话的所有数据保存在会话缓存中;
- * STATEMENT: 可以禁用一级缓存;
- *
- * 第三方缓存整合:
- * 1), 导入第三方缓存包即可;
- * 2), 导入与第三方缓存整合的适配包; 官方有;
- * 3),mapper.xml 中使用自定义缓存
- * <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
- *
- * @throws IOException
- *
- */
- @Test
- public void testSecondLevelCache02() throws IOException{
- SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
- SqlSession openSession = sqlSessionFactory.openSession();
- SqlSession openSession2 = sqlSessionFactory.openSession();
- try{
- //1,
- DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class);
- DepartmentMapper mapper2 = openSession2.getMapper(DepartmentMapper.class);
- Department deptById = mapper.getDeptById(1);
- System.out.println(deptById);
- openSession.close();
- Department deptById2 = mapper2.getDeptById(1);
- System.out.println(deptById2);
- openSession2.close();
- // 第二次查询是从二级缓存中拿到的数据, 并没有发送新的 sql
- }finally{
- }
- }
- @Test
- public void testSecondLevelCache() throws IOException{
- SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
- SqlSession openSession = sqlSessionFactory.openSession();
- SqlSession openSession2 = sqlSessionFactory.openSession();
- try{
- //1,
- EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
- EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
- Employee emp01 = mapper.getEmpById(1);
- System.out.println(emp01);
- openSession.close();
- // 第二次查询是从二级缓存中拿到的数据, 并没有发送新的 sql
- //mapper2.addEmp(new Employee(null, "aaa", "nnn", "0"));
- Employee emp02 = mapper2.getEmpById(1);
- System.out.println(emp02);
- openSession2.close();
- }finally{
- }
- }
- @Test
- public void testFirstLevelCache() throws IOException{
- SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
- SqlSession openSession = sqlSessionFactory.openSession();
- try{
- EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
- Employee emp01 = mapper.getEmpById(1);
- System.out.println(emp01);
- //xxxxx
- //1,sqlSession 不同.
- //SqlSession openSession2 = sqlSessionFactory.openSession();
- //EmployeeMapper mapper2 = openSession2.getMapper(EmployeeMapper.class);
- //2,sqlSession 相同, 查询条件不同
- //3,sqlSession 相同, 两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
- //mapper.addEmp(new Employee(null, "testCache", "cache", "1"));
- //System.out.println("数据添加成功");
- //4,sqlSession 相同, 手动清除了一级缓存(缓存清空)
- //openSession.clearCache();
- Employee emp02 = mapper.getEmpById(1);
- //Employee emp03 = mapper.getEmpById(3);
- System.out.println(emp02);
- //System.out.println(emp03);
- System.out.println(emp01==emp02);
- //openSession2.close();
- }finally{
- openSession.close();
- }
- }
- }
- View Code
- 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>
- <!--
- 1,mybatis 可以使用 properties 来引入外部 properties 配置文件的内容;
- resource: 引入类路径下的资源
- url: 引入网络路径或者磁盘路径下的资源
- -->
- <properties resource="dbconfig.properties"></properties>
- <!--
- 2,settings 包含很多重要的设置项
- setting: 用来设置每一个设置项
- name: 设置项名
- value: 设置项取值
- -->
- <settings>
- <setting name="mapUnderscoreToCamelCase" value="true"/>
- <setting name="jdbcTypeForNull" value="NULL"/>
- <!-- 显式的指定每个我们需要更改的配置的值, 即使他是默认的. 防止版本更新带来的问题 -->
- <setting name="cacheEnabled" value="true"/>
- <setting name="lazyLoadingEnabled" value="true"/>
- <setting name="aggressiveLazyLoading" value="false"/>
- </settings>
- <!-- 3,typeAliases: 别名处理器: 可以为我们的 java 类型起别名
- 别名不区分大小写
- -->
- <typeAliases>
- <!-- 1,typeAlias: 为某个 java 类型起别名
- type: 指定要起别名的类型全类名; 默认别名就是类名小写; employee
- alias: 指定新的别名
- -->
- <!-- <typeAlias type="com.atguigu.mybatis.bean.Employee" alias="emp"/> -->
- <!-- 2,package: 为某个包下的所有类批量起别名
- name: 指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(类名小写),)
- -->
- <package name="com.atguigu.mybatis.bean"/>
- <!-- 3, 批量起别名的情况下, 使用 @Alias 注解为某个类型指定新的别名 -->
- </typeAliases>
- <!--
- 4,environments: 环境们, mybatis 可以配置多种环境 ,default 指定使用某种环境. 可以达到快速切换环境.
- environment: 配置一个具体的环境信息; 必须有两个标签; id 代表当前环境的唯一标识
- transactionManager: 事务管理器;
- type: 事务管理器的类型; JDBC(JdbcTransactionFactory)|MANAGED(ManagedTransactionFactory)
- 自定义事务管理器: 实现 TransactionFactory 接口. type 指定为全类名
- dataSource: 数据源;
- type: 数据源类型; UNPOOLED(UnpooledDataSourceFactory)
- |POOLED(PooledDataSourceFactory)
- |JNDI(JndiDataSourceFactory)
- 自定义数据源: 实现 DataSourceFactory 接口, type 是全类名
- -->
- <environments default="dev_mysql">
- <environment id="dev_mysql">
- <transactionManager type="JDBC"></transactionManager>
- <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="dev_oracle">
- <transactionManager type="JDBC" />
- <dataSource type="POOLED">
- <property name="driver" value="${orcl.driver}" />
- <property name="url" value="${orcl.url}" />
- <property name="username" value="${orcl.username}" />
- <property name="password" value="${orcl.password}" />
- </dataSource>
- </environment>
- </environments>
- <!-- 5,databaseIdProvider: 支持多数据库厂商的;
- type="DB_VENDOR":VendorDatabaseIdProvider
- 作用就是得到数据库厂商的标识(驱动 getDatabaseProductName()),mybatis 就能根据数据库厂商标识来执行不同的 sql;
- MySQL,Oracle,SQL Server,xxxx
- -->
- <databaseIdProvider type="DB_VENDOR">
- <!-- 为不同的数据库厂商起别名 -->
- <property name="MySQL" value="mysql"/>
- <property name="Oracle" value="oracle"/>
- <property name="SQL Server" value="sqlserver"/>
- </databaseIdProvider>
- <!-- 将我们写好的 sql 映射文件 (EmployeeMapper.xml) 一定要注册到全局配置文件 (mybatis-config.xml) 中 -->
- <!-- 6,mappers: 将 sql 映射注册到全局配置中 -->
- <mappers>
- <!--
- mapper: 注册一个 sql 映射
- 注册配置文件
- resource: 引用类路径下的 sql 映射文件
- mybatis/mapper/EmployeeMapper.xml
- url: 引用网路路径或者磁盘路径下的 sql 映射文件
- file:///var/mappers/AuthorMapper.xml
- 注册接口
- class: 引用 (注册) 接口,
- 1, 有 sql 映射文件, 映射文件名必须和接口同名, 并且放在与接口同一目录下;
- 2, 没有 sql 映射文件, 所有的 sql 都是利用注解写在接口上;
- 推荐:
- 比较重要的, 复杂的 Dao 接口我们来写 sql 映射文件
- 不重要, 简单的 Dao 接口为了开发快速可以使用注解;
- -->
- <!-- <mapper resource="mybatis/mapper/EmployeeMapper.xml"/> -->
- <!-- <mapper class="com.atguigu.mybatis.dao.EmployeeMapperAnnotation"/> -->
- <!-- 批量注册: -->
- <package name="com.atguigu.mybatis.dao"/>
- </mappers>
- </configuration>
来源: http://www.bubuko.com/infodetail-2997435.html