mybatis 中应用二级缓存(使用框架本身实现的缓存机制)

来源:互联网 发布:淘宝主营怎么修改 编辑:程序博客网 时间:2024/05/18 00:44

mybatis  中应用二级缓存(使用框架本身实现的缓存机制)


1. 在mybatis的配置文件中,开启二级缓存(cacheEnabled设置为 true).
在mybatis_config.xml文件中,设置如下:

<settings><!-- 开启二级缓存,默认为true(默认二级缓存是开启的) --><setting name="cacheEnabled" value="true"/></settings>

2. 在实体映射文件中,应用二级缓存:
<cache eviction='FIFO' flushInterval='60000' size='512' readOnly='true'/>
其中各项属性代表的含义为:
flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。
readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
eviction配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是 LRU:
1.      LRU – 最近最少使用的:移除最长时间不被使用的对象。
2.      FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
3.      SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
4.      WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

3. 缓存对象执行序列化
由于二级缓存的数据不一定都是存储到内存中,它的存储介质多种多样,所以需要给缓存的对象执行序列化。
如果该类存在父类,那么父类也要实现序列化,类似如下写法:
public class Emp implements Serializable {
}
到这里,二级缓存配置完成。
在应用二级缓存过程中,我们还可以禁用二级缓存:
<!-- 查询全部员工信息 --><select id="findAllEmp" resultType="cn.sz.hcq.pojo.Emp" useCache="false">select empno, ename, job, mgr, hiredate, sal, comm from emp</select>

该statement中设置userCache=false可以禁用当前select语句的二级缓存,即每次查询都是去数据库中查询,默认情况下是true,即该statement使用二级缓存.
还可以刷新二级缓存:
<!-- 查询全部员工信息 --><select id="findAllEmp" resultType="cn.sz.hcq.pojo.Emp" flushCache="true">select empno, ename, job, mgr, hiredate, sal, comm from emp</select>


下面是演示案例:

在mysql数据库中建一张emp表,表的字段如下:


本人演示的项目是Maven项目:

项目结构如下:


IEmpDAO.java为接口,提供查询emp的方法,EmpDAOImpl.java为接口的实现类,MybatisSqlSessionFactory.java为本人创建的获取sqlSession的工具类,Emp.java为实体类,Emp.xml为映射文件,log4j.properties为mybatis打印日志,mybatis_cfg.xml为mybatis主配置文件,Test.java为测试类,pom.xml为maven引入依赖的文件。


我在项目中使用二级缓存,测试的方法是根据员工的编号查询员工的信息。


1、IEmpDAO.java (提供一个根据员工编号查询员工信息的接口方法)

[java] view plain copy
  1. <span style="font-size:18px;">package cn.sz.hcq.dao;  
  2.   
  3. import cn.sz.hcq.pojo.Emp;  
  4.   
  5. public interface IEmpDAO {  
  6.     /** 
  7.      * 根据员工编号查询员工信息 
  8.      *  
  9.      * @param empno 
  10.      * @return 
  11.      */  
  12.     public Emp findAllByEmpno(Integer empno);  
  13.   
  14. }  
  15. </span>  


2、EmpDAOImpl.java 为接口的实现类

[java] view plain copy
  1. <span style="font-size:18px;">package cn.sz.hcq.dao.impl;  
  2.   
  3. import org.apache.ibatis.session.SqlSession;  
  4.   
  5. import cn.sz.hcq.dao.IEmpDAO;  
  6. import cn.sz.hcq.factory.MybatisSqlSessionFactory;  
  7. import cn.sz.hcq.pojo.Emp;  
  8.   
  9. public class EmpDAOImpl implements IEmpDAO {  
  10.   
  11.     public Emp findAllByEmpno(Integer empno) {  
  12.         SqlSession sqlSession = null;  
  13.         try {  
  14.             sqlSession = MybatisSqlSessionFactory.getMySqlSession();  
  15.             return sqlSession.selectOne("cn.sz.hcq.pojo.Emp.findEmpByEmpno",  
  16.                     empno);  
  17.         } catch (Exception e) {  
  18.             e.printStackTrace();  
  19.         } finally {  
  20.             MybatisSqlSessionFactory.closeSqlSession();  
  21.         }  
  22.         return null;  
  23.     }  
  24. }  
  25. </span>  


3、MybatisSqlSessionFactory.java 为本人创建的获取sqlSession的工具类

[java] view plain copy
  1. <span style="font-size:18px;">package cn.sz.hcq.factory;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.Reader;  
  5.   
  6. import org.apache.ibatis.io.Resources;  
  7. import org.apache.ibatis.session.SqlSession;  
  8. import org.apache.ibatis.session.SqlSessionFactory;  
  9. import org.apache.ibatis.session.SqlSessionFactoryBuilder;  
  10.   
  11. public class MybatisSqlSessionFactory {  
  12.     // 配置文件  
  13.     private static final String RESOURCE = "mybatis_cfg.xml";  
  14.     private static Reader reader = null;  
  15.     private static SqlSessionFactoryBuilder builder = null;  
  16.     private static SqlSessionFactory factory = null;  
  17.     // 可以在同一个线程范围内,共享一个对象  
  18.     private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();  
  19.   
  20.     // 静态代码块(类加载的时候执行一次)  
  21.     static {  
  22.         try {  
  23.             reader = Resources.getResourceAsReader(RESOURCE);  
  24.             builder = new SqlSessionFactoryBuilder();  
  25.             factory = builder.build(reader);  
  26.         } catch (IOException e) {  
  27.             e.printStackTrace();  
  28.         }  
  29.     }  
  30.   
  31.     public static SqlSession getMySqlSession() {  
  32.         // 从本地线程中获取session连接  
  33.         SqlSession sqlSession = threadLocal.get();  
  34.         // 连接为空则创建连接,并将该连接添加到本地线程中去  
  35.         if (sqlSession == null) {  
  36.             if (factory == null) {  
  37.                 rebuildFactory();  
  38.             }  
  39.             sqlSession = factory.openSession();  
  40.         }  
  41.         threadLocal.set(sqlSession);  
  42.         return sqlSession;  
  43.     }  
  44.   
  45.     // 创建工厂  
  46.     public static void rebuildFactory() {  
  47.         try {  
  48.             reader = Resources.getResourceAsReader(RESOURCE);  
  49.             builder = new SqlSessionFactoryBuilder();  
  50.             factory = builder.build(reader);  
  51.         } catch (IOException e) {  
  52.             e.printStackTrace();  
  53.         }  
  54.     }  
  55.   
  56.     // 关闭连接  
  57.     public static void closeSqlSession() {  
  58.         SqlSession sqlSession = threadLocal.get();  
  59.         if (sqlSession != null) {  
  60.             // 关闭session  
  61.             sqlSession.close();  
  62.         }  
  63.         // 同时将本地线程中置为null(防止用户再次调用时出现空的session)  
  64.         threadLocal.set(null);  
  65.     }  
  66.   
  67. }  
  68. </span>  


4、Emp.java为实体类

[java] view plain copy
  1. <span style="font-size:18px;">package cn.sz.hcq.pojo;  
  2.   
  3. import java.io.Serializable;  
  4. import java.util.Date;  
  5.   
  6. public class Emp implements Serializable {  
  7.     private Integer empno;  
  8.     private String ename;  
  9.     private String job;  
  10.     private Integer mgr;  
  11.     private Date hiredate;  
  12.     private Double sal;  
  13.     private Double comm;  
  14.   
  15.     public Integer getEmpno() {  
  16.         return empno;  
  17.     }  
  18.   
  19.     public void setEmpno(Integer empno) {  
  20.         this.empno = empno;  
  21.     }  
  22.   
  23.     public String getEname() {  
  24.         return ename;  
  25.     }  
  26.   
  27.     public void setEname(String ename) {  
  28.         this.ename = ename;  
  29.     }  
  30.   
  31.     public String getJob() {  
  32.         return job;  
  33.     }  
  34.   
  35.     public void setJob(String job) {  
  36.         this.job = job;  
  37.     }  
  38.   
  39.     public Integer getMgr() {  
  40.         return mgr;  
  41.     }  
  42.   
  43.     public void setMgr(Integer mgr) {  
  44.         this.mgr = mgr;  
  45.     }  
  46.   
  47.     public Date getHiredate() {  
  48.         return hiredate;  
  49.     }  
  50.   
  51.     public void setHiredate(Date hiredate) {  
  52.         this.hiredate = hiredate;  
  53.     }  
  54.   
  55.     public Double getSal() {  
  56.         return sal;  
  57.     }  
  58.   
  59.     public void setSal(Double sal) {  
  60.         this.sal = sal;  
  61.     }  
  62.   
  63.     public Double getComm() {  
  64.         return comm;  
  65.     }  
  66.   
  67.     public void setComm(Double comm) {  
  68.         this.comm = comm;  
  69.     }  
  70.   
  71. }  
  72. </span>  


5、Emp.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="cn.sz.hcq.pojo.Emp"><!-- 配置二级缓存 --><cache eviction='FIFO' flushInterval='60000' size='512' readOnly='true' /><!-- 根据员工编号查询员工信息 --><select id="findEmpByEmpno" parameterType="java.lang.Integer"resultType="cn.sz.hcq.pojo.Emp" useCache="true">selectempno,ename,job,mgr,sal,comm,hiredate fromempwhereempno=#{empno}</select></mapper>


6、log4j.properties为mybatis打印日志

[plain] view plain copy
  1. <span style="font-size:18px;">log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
  2. log4j.appender.stdout.Target=System.out  
  3. log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
  4. log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n  
  5. log4j.appender.file=org.apache.log4j.FileAppender  
  6.   
  7. log4j.appender.file.File=d:/log.txt  
  8.   
  9. log4j.appender.file.layout=org.apache.log4j.PatternLayout  
  10.   
  11. log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss}  %m%n  
  12. log4j.rootLogger=debug,file,stdout  
  13. #fatal-->error-->warn-->info-->debug  
  14.   
  15. log4j.logger.com.ibatis=DEBUG  
  16. log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG  
  17. log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG  
  18. log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG  
  19. log4j.logger.java.sql.Connection=DEBUG  
  20. log4j.logger.java.sql.Statement=DEBUG  
  21. log4j.logger.java.sql.PreparedStatement=DEBUG</span>  


7、mybatis_cfg.xml为mybatis主配置文件

<?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><!-- 配置的参数 --><settings><!-- 开启二级缓存,默认为true(默认二级缓存是开启的) --><setting name="cacheEnabled" value="true" /></settings><!--数据源 --><environments default="myconn"><environment id="myconn"><!--事务管理方式 --><transactionManager type="JDBC"></transactionManager><!--数据库连接参数 --><dataSource type="POOLED"><!-- type:数据源连接的方式 ,POOLED:连接池方式, UNPOOLED: 非连接池的方式 ,JNDI:java命名与目录接口方式 --><property name="driver" value="org.gjt.mm.mysql.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/db"></property><property name="username" value="root"></property><property name="password" value="root"></property></dataSource></environment></environments><!-- 引入实体映射文件 --><mappers><mapper resource="cn/sz/hcq/pojo/Emp.xml" /></mappers></configuration>


8、pom.xml为maven引入依赖的文件

[html] view plain copy
  1. <span style="font-size:18px;"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  2.     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  3.     <modelVersion>4.0.0</modelVersion>  
  4.     <groupId>cn.sz.hcq.pro</groupId>  
  5.     <artifactId>Mybatis_ehcache_06</artifactId>  
  6.     <version>0.0.1-SNAPSHOT</version>  
  7.     <packaging>war</packaging>  
  8.     <dependencies>  
  9.         <!-- mysql数据库驱动 -->  
  10.         <dependency>  
  11.             <groupId>mysql</groupId>  
  12.             <artifactId>mysql-connector-java</artifactId>  
  13.             <version>5.0.8</version>  
  14.         </dependency>  
  15.         <!--mybatis依赖 -->  
  16.         <dependency>  
  17.             <groupId>org.mybatis</groupId>  
  18.             <artifactId>mybatis</artifactId>  
  19.             <version>3.2.3</version>  
  20.         </dependency>  
  21.   
  22.         <!-- 日志记录 -->  
  23.         <dependency>  
  24.             <groupId>log4j</groupId>  
  25.             <artifactId>log4j</artifactId>  
  26.             <version>1.2.17</version>  
  27.         </dependency>  
  28.         <dependency>  
  29.             <groupId>cglib</groupId>  
  30.             <artifactId>cglib</artifactId>  
  31.             <version>2.2.2</version>  
  32.         </dependency>  
  33.         <dependency>  
  34.             <groupId>org.slf4j</groupId>  
  35.             <artifactId>slf4j-log4j12</artifactId>  
  36.             <version>1.7.5</version>  
  37.         </dependency>  
  38.   
  39.     </dependencies>  
  40. </project></span>  


9、Test.java为测试类

[java] view plain copy
  1. <span style="font-size:18px;">package cn.sz.hcq.test;  
  2.   
  3. import cn.sz.hcq.dao.IEmpDAO;  
  4. import cn.sz.hcq.dao.impl.EmpDAOImpl;  
  5. import cn.sz.hcq.pojo.Emp;  
  6.   
  7. public class Test {  
  8.     public static void main(String[] args) {  
  9.         IEmpDAO empDAO = new EmpDAOImpl();  
  10.         // 查询编号为7788的员工  
  11.         // 这里我们连续调用两次方法,发现sql语句就执行一次  
  12.         empDAO.findAllByEmpno(7788);  
  13.   
  14.         Emp emp = empDAO.findAllByEmpno(7788);  
  15.           
  16.         System.out.println("姓名:" + emp.getEname() + ",员工号:" + emp.getEmpno());  
  17.     }  
  18. }  
  19. </span>  

在测试中我们两次调用查询方法,在控制台的日志信息中发现我们的sql语句只是执行了一次,因为第二次查询的时候数据从二级缓存中取出(第一次查询时将数据保存到了二级缓存中)。

下面是日志的截图:




阅读全文
0 0