天天看點

mybatis 中應用二級緩存(使用架構本身實作的緩存機制)

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表,表的字段如下:

mybatis 中應用二級緩存(使用架構本身實作的緩存機制)

本人示範的項目是Maven項目:

項目結構如下:

mybatis 中應用二級緩存(使用架構本身實作的緩存機制)

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. import cn.sz.hcq.pojo.Emp;  
  3. public interface IEmpDAO {  
  4.     public Emp findAllByEmpno(Integer empno);  
  5. }  
  6. </span>  

2、EmpDAOImpl.java 為接口的實作類

[java]  view plain  copy

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

3、MybatisSqlSessionFactory.java 為本人建立的擷取sqlSession的工具類

[java]  view plain  copy

  1. <span style="font-size:18px;">package cn.sz.hcq.factory;  
  2. import java.io.IOException;  
  3. import java.io.Reader;  
  4. import org.apache.ibatis.io.Resources;  
  5. import org.apache.ibatis.session.SqlSession;  
  6. import org.apache.ibatis.session.SqlSessionFactory;  
  7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;  
  8. public class MybatisSqlSessionFactory {  
  9.     // 配置檔案  
  10.     private static final String RESOURCE = "mybatis_cfg.xml";  
  11.     private static Reader reader = null;  
  12.     private static SqlSessionFactoryBuilder builder = null;  
  13.     private static SqlSessionFactory factory = null;  
  14.     // 可以在同一個線程範圍内,共享一個對象  
  15.     private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();  
  16.     // 靜态代碼塊(類加載的時候執行一次)  
  17.     static {  
  18.         try {  
  19.             reader = Resources.getResourceAsReader(RESOURCE);  
  20.             builder = new SqlSessionFactoryBuilder();  
  21.             factory = builder.build(reader);  
  22.         } catch (IOException e) {  
  23.             e.printStackTrace();  
  24.         }  
  25.     }  
  26.     public static SqlSession getMySqlSession() {  
  27.         // 從本地線程中擷取session連接配接  
  28.         SqlSession sqlSession = threadLocal.get();  
  29.         // 連接配接為空則建立連接配接,并将該連接配接添加到本地線程中去  
  30.         if (sqlSession == null) {  
  31.             if (factory == null) {  
  32.                 rebuildFactory();  
  33.             }  
  34.             sqlSession = factory.openSession();  
  35.         }  
  36.         threadLocal.set(sqlSession);  
  37.         return sqlSession;  
  38.     }  
  39.     // 建立工廠  
  40.     public static void rebuildFactory() {  
  41.         try {  
  42.             reader = Resources.getResourceAsReader(RESOURCE);  
  43.             builder = new SqlSessionFactoryBuilder();  
  44.             factory = builder.build(reader);  
  45.         } catch (IOException e) {  
  46.             e.printStackTrace();  
  47.         }  
  48.     }  
  49.     // 關閉連接配接  
  50.     public static void closeSqlSession() {  
  51.         SqlSession sqlSession = threadLocal.get();  
  52.         if (sqlSession != null) {  
  53.             // 關閉session  
  54.             sqlSession.close();  
  55.         }  
  56.         // 同時将本地線程中置為null(防止使用者再次調用時出現空的session)  
  57.         threadLocal.set(null);  
  58.     }  
  59. }  
  60. </span>  

4、Emp.java為實體類

[java]  view plain  copy

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

  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. log4j.appender.file.File=d:/log.txt  
  7. log4j.appender.file.layout=org.apache.log4j.PatternLayout  
  8. log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss}  %m%n  
  9. log4j.rootLogger=debug,file,stdout  
  10. #fatal-->error-->warn-->info-->debug  
  11. log4j.logger.com.ibatis=DEBUG  
  12. log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG  
  13. log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG  
  14. log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG  
  15. log4j.logger.java.sql.Connection=DEBUG  
  16. log4j.logger.java.sql.Statement=DEBUG  
  17. 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.         <dependency>  
  23.             <groupId>log4j</groupId>  
  24.             <artifactId>log4j</artifactId>  
  25.             <version>1.2.17</version>  
  26.         </dependency>  
  27.         <dependency>  
  28.             <groupId>cglib</groupId>  
  29.             <artifactId>cglib</artifactId>  
  30.             <version>2.2.2</version>  
  31.         </dependency>  
  32.         <dependency>  
  33.             <groupId>org.slf4j</groupId>  
  34.             <artifactId>slf4j-log4j12</artifactId>  
  35.             <version>1.7.5</version>  
  36.         </dependency>  
  37.     </dependencies>  
  38. </project></span>  

9、Test.java為測試類

[java]  view plain  copy

  1. <span style="font-size:18px;">package cn.sz.hcq.test;  
  2. import cn.sz.hcq.dao.IEmpDAO;  
  3. import cn.sz.hcq.dao.impl.EmpDAOImpl;  
  4. import cn.sz.hcq.pojo.Emp;  
  5. public class Test {  
  6.     public static void main(String[] args) {  
  7.         IEmpDAO empDAO = new EmpDAOImpl();  
  8.         // 查詢編号為7788的員工  
  9.         // 這裡我們連續調用兩次方法,發現sql語句就執行一次  
  10.         empDAO.findAllByEmpno(7788);  
  11.         Emp emp = empDAO.findAllByEmpno(7788);  
  12.         System.out.println("姓名:" + emp.getEname() + ",員工号:" + emp.getEmpno());  
  13.     }  
  14. }  
  15. </span>  

在測試中我們兩次調用查詢方法,在控制台的日志資訊中發現我們的sql語句隻是執行了一次,因為第二次查詢的時候資料從二級緩存中取出(第一次查詢時将資料儲存到了二級緩存中)。

下面是日志的截圖:

mybatis 中應用二級緩存(使用架構本身實作的緩存機制)

繼續閱讀