您的位置:首页 > 其它

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

2017-11-17 13:06 746 查看
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 {

/**

* 根据员工编号查询员工信息

*

* @param empno

* @return

*/

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语句只是执行了一次,因为第二次查询的时候数据从二级缓存中取出(第一次查询时将数据保存到了二级缓存中)。

下面是日志的截图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐