缓存分类
一级缓存
事务范围: 缓存只能被当前事务访问. 缓存的生命周期
依赖于事务的生命周期当事务结束时, 缓存也就结束生命周期.
在此范围下, 缓存的介质是内存.
二级缓存
进程范围: 缓存被进程内的所有事务共享. 这些事务有
可能是并发访问缓存, 因此必须对缓存采取必要的事务隔离机制.
缓存的生命周期依赖于进程的生命周期, 进程结束时,
缓存也就结束了生命周期. 进程范围的缓存可能会存放大量的数据,
所以存放的介质可以是内存或硬盘.
三级缓存
集群范围: 在集群环境中, 缓存被一个机器或者多个机器的进程共享.
缓存中的数据被复制到集群环境中的每个进程节点,
进程间通过远程通信来保证缓存中的数据的一致性,
缓存中的数据通常采用对象的松散数据形式
MyBatis 支持一级缓存和二级缓存, 在实际开发中, 实际上很少使用到 MyBatis 自带的缓存, 大部分情况下, 缓存都是使用 EHCache,MemoryCache,Redis 等等来实现缓存.
所需依赖
- <dependencies>
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.4.6</version>
- </dependency>
- <dependency>
- <groupId>org.mybatis.caches</groupId>
- <artifactId>mybatis-ehcache</artifactId>
- <version>1.1.0</version>
- </dependency>
- <dependency>
- <groupId.NET.sf.ehcache</groupId>
- <artifactId>ehcache</artifactId>
- <version>1.5.0</version>
- </dependency>
- <dependency>
- <groupId>MySQL</groupId>
- <artifactId>MySQL-connector-java</artifactId>
- <version>5.1.41</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.7.25</version>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.17</version>
- </dependency>
- </dependencies>
全局配置文件 mybatis-cfg.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="db.properties"/>
- <!-- 自定义别名 -->
- <typeAliases>
- <typeAlias type="com.zsl.pojo.Emp" alias="emp"/>
- </typeAliases>
- <!-- 环境 -->
- <environments default="development">
- <environment id="development">
- <transactionManager type="JDBC"/>
- <dataSource type="POOLED">
- <property name="driver" value="${driver}"/>
- <property name="url" value="${url}"/>
- <property name="username" value="${userName}"/>
- <property name="password" value="${password}"/>
- </dataSource>
- </environment>
- </environments>
- <!-- 注册映射文件 -->
- <mappers>
- <mapper resource="EmpMapper.xml"/>
- <!-- <package name="包名"/> -->
- </mappers>
- </configuration>
EmpMapper 接口
- public interface EmpMapper {
- public List<Emp> queryE();
- public Emp queryA(@Param("empno")Integer empno);
- }
EmpMapper.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.zsl.dao.EmpMapper">
- <select id="queryE" resultType="emp">
- SELECT * FROM emp
- </select>
- <select id="queryA" resultType="emp">
- SELECT * FROM emp
- <where>
- <if test="empno != null">
- empno = #{empno}
- </if>
- </where>
- </select>
- </mapper>
日志配置文件 log4j.properties
- log4j.rootCategory=DEBUG, consoleR , fileR
- log4j.appender.consoleR=org.apache.log4j.ConsoleAppender
- log4j.appender.consoleR.layout=org.apache.log4j.PatternLayout
- log4j.appender.consoleR.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n
- log4j.appender.fileR=org.apache.log4j.DailyRollingFileAppender
- log4j.appender.fileR.File=D:\\logs\\log.log
- log4j.appender.fileR.layout=org.apache.log4j.PatternLayout
- log4j.appender.fileR.layout.ConversionPattern=%d-[TS] %p %t %c - %m%n
- log4j.logger.com.neusoft=DEBUG
- log4j.logger.com.opensymphony.oscache=ERROR
- log4j.logger.NET.sf.navigator=ERROR
- log4j.logger.org.apache.commons=ERROR
- log4j.logger.org.apache.struts=WARN
- log4j.logger.org.displaytag=ERROR
- log4j.logger.org.springframework=DEBUG
- log4j.logger.com.ibatis.db=WARN
- log4j.logger.org.apache.velocity=FATAL
- log4j.logger.com.canoo.webtest=WARN
- log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
- log4j.logger.org.hibernate=DEBUG
- log4j.logger.org.logicalcobwebs=WARN
这里通过开启日志 DEBUG 级别来观察
一级缓存
MyBatis 中一级缓存是基于 SqlSession 的
一级缓存是 Mybatis 自带的不用带入第三方 jar 包就可以使用
- // 首先会从 一级缓存查询有没有参数对应的数据, 没有的话直接查询数据库然后将数据保存到一级缓存中, 如果有直接返回
- // 缓存存储的数据的结构是一个类似于 map 的结构 key 是 sql+xxx
测试 Test 类
- public class Test {
- public static void main(String[] args) throws IOException {
- // 第一次查询, 从数据库中查询的数据会保存在一级缓存中
- SqlSession session = DbUtils.getSession();
- EmpMapper mapper = session.getMapper(EmpMapper.class);
- List<Emp> list = mapper.queryE();
- for (Emp emp : list) {
- System.out.println("ename:"+emp.getEname()+",job:"+emp.getJob()+" ");
- }
- System.out.println("-------- 分割线 --------");
- // 先查看缓存中是否有该数据, 如果没有就从数据库中查询
- Emp emp = mapper.queryA(7900);
- System.out.println("ename:"+emp.getEname()+",job:"+emp.getJob()+" ");
- System.out.println("-------- 分割线 --------");
- // 之前查询的有, 直接从缓存中获取
- emp = mapper.queryA(7900);
- System.out.println("ename:"+emp.getEname()+",job:"+emp.getJob()+" ");
- session.close();
- }
- }
查看日志输出
一级缓存是基于 session 的, 从 SqlSessionFactory 对象. openSession() 开始
// 通过 SqlSessionFactory 对象获取 SQLSession 对象
至到 session.close() 这次会话结束期间有效, session.close() 后就清除了所有的一级缓存.
二级缓存
二级缓存基于 SqlSessionFactory, 一级缓存的作用域只是 SqlSession, 范围比较下, 用到的不多. 二级缓存是进程级别的缓存, 用的比较普遍, 二级缓存 mybatis 本身没有提供, 常用的主键有 Ehcache 和 Redis, 这次使用的是 Ehcache.
- <!-- 该映射文件中的所有查询都会开启二级缓存 -->
- <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
测试类 Test
- public class Test {
- public static void main(String[] args) throws IOException {
- // 第一次查询
- // 1. 通过 Resources 对象加载配置文件
- InputStream inputStream = Resources.getResourceAsStream("mybatis-cfg.xml");
- // 2. 获取 SqlSessionFactory 对象
- SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
- // 3. 通过 SqlSessionFactory 对象获取 SQLSession 对象
- SqlSession session = factory.openSession();
- EmpMapper mapper = session.getMapper(EmpMapper.class);
- Emp emp = mapper.queryA(7900);
- System.out.println("ename:" + emp.getEname() + ",job:" + emp.getJob() + " ");
- session.close();
- // session 已关闭
- System.out.println("-------- 分割线 --------");
- // 再次打开 session
- session = factory.openSession();
- mapper = session.getMapper(EmpMapper.class);
- emp = mapper.queryA(7900);
- System.out.println("ename:" + emp.getEname() + ",job:" + emp.getJob() + " ");
- session.close();
- }
- }
二级缓存是进程级别的所以 session 会话关闭不会清除二级缓存, 只能清除一级缓存, 二级缓存不是基于 session 的, 而是基于 SqlSessionFactory 的
数据库的 DCL( COMMIT,ROLLBACK,GRANT,REVOKE 等语句) 操作会清空一二级缓存
Ehcach 是会话级别的缓存
* 1. 先查询一级缓存中是否有数据
* 有则返回查询到的数据, 没有的话就会查询数据库并将结果保存到一级缓存中
2. 一级缓存没有 查询二级缓存中是否有数据
有则返回查询到的数据, 没有的话查询数据库并将结果保存到一级和二级缓存中
在 mybatis 中只要执行了 commit 操作 那么就会清空一二级缓存
hibernate 中是不一样的
来源: http://www.bubuko.com/infodetail-3122163.html