Mybaits (13) cache

I. Overview

  Like most MyBatis persistence layer frameworks, but also it provides a caching strategy to reduce the number of database queries by caching strategies to improve performance. 

  MyBatis into cache and a secondary cache, but also can configure the settings for the cache.

Second, the cache

 1 Introduction

 Level cache is cached on SqlSession, as long as SqlSession no flush or close, it exists. By default, that is, without any configuration, MyBatis will open a cache, that is, for SqlSession level cache, the cache does not need POJO object serialization (implement java.io.Serializable).

 2. Test, prove the existence of a cache

 (1) write test classes

 

@Test
     public  void   testCache () {
         // 5. The proxy object creates a Dao 
        roleDao = session.getMapper (IRoleDao. Class );
        logger.info ( "First get ..." );
        Role role = roleDao.getRole (1L );
        logger.info ( "second acquisition ..." );
        Role role1 = roleDao.getRole (1L );

    }

(2) View Log

 

 

(3) analysis

  Although the code to get the same object twice, but in fact only one SQL, the reason is the code uses the same SqlSession object to obtain data, when a SqlSession first get through Sql objects and parameters, it will be its cache up, and if the next Sql parameters are changed, and there is no cache timeout or statement needs to be refreshed, it will obtain the data from the cache instead of getting through the Sql.

 

   When a cache is a cache SqlSession range, when you call SqlSession modification, addition, deletion, commit (), close (), etc. will clear the cache. If sqlSession to perform commit operations (insert, update, delete), empty the cache SqlSession the purpose of doing so in order to allow stored in the cache is the latest information, avoid dirty reads.

(4) Clear cache test

Empty the cache

@Test
     public  void   testClearCache () {
         // 5. The proxy object creates a Dao 
        roleDao = session.getMapper (IRoleDao. Class );
        logger.info ( "First get ..." );
        Role Role = roleDao.getRole (1L );
         // This method can also be empty the cache 
        session.clearCache ();
        logger.info ( "second acquisition ..." );
        Role role1 = roleDao.getRole (1L );
        logger.info(role==role1);

    }

 

 As can be seen from the log sql performed twice, the last execution result is false, cache is cleared. SqlSession for different objects can not be shared, in order to share the same target SqlSession between cache is sometimes necessary to open the secondary cache, the cache is turned on two simple requiring only the addition code on mapping file: <cache />, this time will MyBatis and deserialization sequence corresponding entity class (POJO), also requires a POJO is a serializable object, implement java.io.Serializable.

Second, the secondary cache

1, the concept of

  It refers to the cache MyBatis SqlSessionFactory objects. Since the creation of the same object SQLSession SqlSessionFactory share its memory.

  A mapper mapping the secondary cache level cache, a plurality SqlSession sql statement to operate the same Mapper maps, can share SqlSession plurality of secondary cache, the secondary cache across SqlSession 

2, the secondary cache test

(1) opening and closing of the secondary cache

  Open second-level cache file SqlMapConfig.xml 

 

<settings>
        <setting name="lazyLoadingEnabled" value="true" />
        <setting name="aggressiveLazyLoading" value="false" />
        <!-- 开启二级缓存 -->
        <setting name="cacheEnabled" value="true"/>
    </settings>

 

  因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为
false 代表不开启二级缓存。 

(2)配置相关的 Mapper 映射文件

  标签表示当前这个 mapper 映射将使用二级缓存,区分的标准就看 mapper 的 namespace 值。 
<?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.xhbjava.dao.IUserDao">
    <cache></cache>
    <resultMap type="com.xhbjava.domain.User" id="userMapper">

        <id column="id" property="id" />
        <result column="user_name" property="userName" />
        <result column="real_name" property="realName" />
        <result column="sex" property="sex"
            typeHandler="com.xhbjava.typeHandler.SexTypeHandler" />
        <result column="mobile" property="moble" />
        <result column="email" property="email" />
        <result column="position" property="position" />
        <result column="note" property="note" />
        <collection property="roleList" column="id"
            fetchType="lazy" select="com.xhbjava.dao.IRoleDao.findRoleByUserId" />
    </resultMap>
    <select id="getUser" parameterType="long" resultMap="userMapper">
        select id,
        user_name, real_name, sex, moble, email, note from t_user where
        id
        =#{id}
    </select>
    <select id="findUserByRoleId" parameterType="long"
        resultMap="userMapper">
        select u.id, u.user_name, u.real_name, u.sex, u.moble,
        u.email, u.note
        from
        t_user u , t_user_role ur where u.id = ur.user_id
        and ur.role_id =#{roleId}
    </select>

</mapper>

(3)配置 statement 上面的 useCache 属性

<select id="getUser" parameterType="long" resultMap="userMapper" useCache="true">
        select id,
        user_name, real_name, sex, moble, email, note from t_user where
        id
        =#{id}
    </select>

  将 UserDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。

  注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。

(4)编写测试类进行测试

@Test
	public void  testSecondLevelCache() {
		// 5.创建Dao的代理对象
		 session = factory.openSession(true);
	     userDao = session.getMapper(IUserDao.class);
		logger.info("第一次获取...");
		User user = userDao.getUser(1L);
		//一级缓存消失
		session.close();
		logger.info("第二次获取...");
		// 5.创建Dao的代理对象
		session11 = factory.openSession(true);
		userDao1 = session11.getMapper(IUserDao.class);
		User user1 = userDao1.getUser(1L);
		logger.info(user==user1);

	}

 

 

  经过上面的测试,我们发现执行了两次查询,并且在执行第一次查询后,我们关闭了一级缓存,再去执行第二次查询时,我们发现并没有对数据库发出 sql 语句,所以此时的数据就只能是来自于我们所说的二级缓存。 

注意:使用二级缓存,缓存的类一定要实现 java.io.Serializable 接口,这样可以使用序列化方式来保存对象。 

三、缓存配置项、自定义和引用

1.cache元素配置项:

 

属性 说明 取值 备注
blocking 是否使用阻塞性缓存,在读写时会加入JNI的锁进行操作 true|false,默认false 保证读写安全性,但加锁后性能不佳
readOnly 缓存内容是否只读 true|false,默认false 如果是只读,不会因为多个线程读写造成不一致
eviction

缓存策略:

LRU最近最少使用:移除最长时间不被使用的对象

FIFO先进先出:按照对象进入缓存的顺序移除

SOFT软引用:移除基于垃圾回收器状态和软引用规则对象

WEAK弱引用:积极移除基于垃圾收集器状态和弱引用规则对象

默认false  
flushInterval

这是一个整数,以毫秒为单位,比如1分钟刷新一次,则配置60000.

默认为null,也就是没有刷新时间,只有执行update,inset和delete

时才会刷新。

正整数

超过设置的整数后缓存消失,不再读取缓存,而是执行SQL

取回数据。

type 自定义缓存类。要求实现org.apache.ibatis.cache.Cache 用于自定义缓存类  
size 缓存对象个数 正整数。默认是1024  

2.自定义缓存类

  在实际工作中,我们可以使用Redis,MongoDB或者其他常用的缓存,假设我们在存在Redis的一个缓存实现类RedisCache,我们可以这样配置:

<cache type="XXX.XX.RedisCache">

<property name="host" value="localhost" />

</cache>

这样配置后,MyBatis就会启用缓存,同时调用setHost(String host)方法,去设置配置的内容。

上面的配置时通用的,对于一些语句也需要自定义,比如一些查询不想让它们进行缓存,我们可以如下配置:

<select ... flushCache="false" userCache="true">

<insert ... flushCache="true" >

<update... flushCache="true" >

<delete ... flushCache="true" >

以上是默认配置,我们可以根据需要去修改。flashCache代表是否刷新缓存,对于select、insert、update和delete都是有效的。useCache是select特有的,代表是否启用缓存。

这里都是在一个映射配置文件中配置的,比如IUserDao.xml,其他的映射配置文件不能使用,如果其他映射配置文件需要使用同样的配置,则可以引用缓存的配置:

<cache-ref namespace="XXX.XX.IUserDao"/>这样就可以引用对应映射文件的cache元素的配置了。

UserDao.xml 映射文件中的

Guess you like

Origin www.cnblogs.com/xhbJava/p/12390119.html