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
- <span style="font-size:18px;">package cn.sz.hcq.dao;
- import cn.sz.hcq.pojo.Emp;
- public interface IEmpDAO {
- public Emp findAllByEmpno(Integer empno);
- }
- </span>
2、EmpDAOImpl.java 為接口的實作類
[java] view plain copy
- <span style="font-size:18px;">package cn.sz.hcq.dao.impl;
- import org.apache.ibatis.session.SqlSession;
- import cn.sz.hcq.dao.IEmpDAO;
- import cn.sz.hcq.factory.MybatisSqlSessionFactory;
- import cn.sz.hcq.pojo.Emp;
- public class EmpDAOImpl implements IEmpDAO {
- public Emp findAllByEmpno(Integer empno) {
- SqlSession sqlSession = null;
- try {
- sqlSession = MybatisSqlSessionFactory.getMySqlSession();
- return sqlSession.selectOne("cn.sz.hcq.pojo.Emp.findEmpByEmpno",
- empno);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- MybatisSqlSessionFactory.closeSqlSession();
- }
- return null;
- }
- }
- </span>
3、MybatisSqlSessionFactory.java 為本人建立的擷取sqlSession的工具類
[java] view plain copy
- <span style="font-size:18px;">package cn.sz.hcq.factory;
- import java.io.IOException;
- import java.io.Reader;
- import org.apache.ibatis.io.Resources;
- import org.apache.ibatis.session.SqlSession;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.apache.ibatis.session.SqlSessionFactoryBuilder;
- public class MybatisSqlSessionFactory {
- // 配置檔案
- private static final String RESOURCE = "mybatis_cfg.xml";
- private static Reader reader = null;
- private static SqlSessionFactoryBuilder builder = null;
- private static SqlSessionFactory factory = null;
- // 可以在同一個線程範圍内,共享一個對象
- private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
- // 靜态代碼塊(類加載的時候執行一次)
- static {
- try {
- reader = Resources.getResourceAsReader(RESOURCE);
- builder = new SqlSessionFactoryBuilder();
- factory = builder.build(reader);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public static SqlSession getMySqlSession() {
- // 從本地線程中擷取session連接配接
- SqlSession sqlSession = threadLocal.get();
- // 連接配接為空則建立連接配接,并将該連接配接添加到本地線程中去
- if (sqlSession == null) {
- if (factory == null) {
- rebuildFactory();
- }
- sqlSession = factory.openSession();
- }
- threadLocal.set(sqlSession);
- return sqlSession;
- }
- // 建立工廠
- public static void rebuildFactory() {
- try {
- reader = Resources.getResourceAsReader(RESOURCE);
- builder = new SqlSessionFactoryBuilder();
- factory = builder.build(reader);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- // 關閉連接配接
- public static void closeSqlSession() {
- SqlSession sqlSession = threadLocal.get();
- if (sqlSession != null) {
- // 關閉session
- sqlSession.close();
- }
- // 同時将本地線程中置為null(防止使用者再次調用時出現空的session)
- threadLocal.set(null);
- }
- }
- </span>
4、Emp.java為實體類
[java] view plain copy
- <span style="font-size:18px;">package cn.sz.hcq.pojo;
- import java.io.Serializable;
- import java.util.Date;
- public class Emp implements Serializable {
- private Integer empno;
- private String ename;
- private String job;
- private Integer mgr;
- private Date hiredate;
- private Double sal;
- private Double comm;
- public Integer getEmpno() {
- return empno;
- }
- public void setEmpno(Integer empno) {
- this.empno = empno;
- }
- public String getEname() {
- return ename;
- }
- public void setEname(String ename) {
- this.ename = ename;
- }
- public String getJob() {
- return job;
- }
- public void setJob(String job) {
- this.job = job;
- }
- public Integer getMgr() {
- return mgr;
- }
- public void setMgr(Integer mgr) {
- this.mgr = mgr;
- }
- public Date getHiredate() {
- return hiredate;
- }
- public void setHiredate(Date hiredate) {
- this.hiredate = hiredate;
- }
- public Double getSal() {
- return sal;
- }
- public void setSal(Double sal) {
- this.sal = sal;
- }
- public Double getComm() {
- return comm;
- }
- public void setComm(Double comm) {
- this.comm = comm;
- }
- }
- </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">
select
empno,ename,job,mgr,sal,comm,hiredate from
emp
where
empno=#{empno}
</select>
</mapper>
6、log4j.properties為mybatis列印日志
[plain] view plain copy
- <span style="font-size:18px;">log4j.appender.stdout=org.apache.log4j.ConsoleAppender
- log4j.appender.stdout.Target=System.out
- log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
- log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n
- log4j.appender.file=org.apache.log4j.FileAppender
- log4j.appender.file.File=d:/log.txt
- log4j.appender.file.layout=org.apache.log4j.PatternLayout
- log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %m%n
- log4j.rootLogger=debug,file,stdout
- #fatal-->error-->warn-->info-->debug
- log4j.logger.com.ibatis=DEBUG
- log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
- log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
- log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
- log4j.logger.java.sql.Connection=DEBUG
- log4j.logger.java.sql.Statement=DEBUG
- 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
- <span style="font-size:18px;"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>cn.sz.hcq.pro</groupId>
- <artifactId>Mybatis_ehcache_06</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>war</packaging>
- <dependencies>
- <!-- mysql資料庫驅動 -->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>5.0.8</version>
- </dependency>
- <!--mybatis依賴 -->
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- <version>3.2.3</version>
- </dependency>
- <!-- 日志記錄 -->
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.17</version>
- </dependency>
- <dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
- <version>2.2.2</version>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.7.5</version>
- </dependency>
- </dependencies>
- </project></span>
9、Test.java為測試類
[java] view plain copy
- <span style="font-size:18px;">package cn.sz.hcq.test;
- import cn.sz.hcq.dao.IEmpDAO;
- import cn.sz.hcq.dao.impl.EmpDAOImpl;
- import cn.sz.hcq.pojo.Emp;
- public class Test {
- public static void main(String[] args) {
- IEmpDAO empDAO = new EmpDAOImpl();
- // 查詢編号為7788的員工
- // 這裡我們連續調用兩次方法,發現sql語句就執行一次
- empDAO.findAllByEmpno(7788);
- Emp emp = empDAO.findAllByEmpno(7788);
- System.out.println("姓名:" + emp.getEname() + ",員工号:" + emp.getEmpno());
- }
- }
- </span>
在測試中我們兩次調用查詢方法,在控制台的日志資訊中發現我們的sql語句隻是執行了一次,因為第二次查詢的時候資料從二級緩存中取出(第一次查詢時将資料儲存到了二級緩存中)。
下面是日志的截圖: