Mybatis使用Redis二级缓存

在Mybatis中允许开发者自定义自己的缓存,本文将使用Redis作为Mybatis的二级缓存。在Mybatis中定义二级缓存,需要如下配置:

1、 MyBatis支持二级缓存的总开关:全局配置变量参数“cacheEnabled=true”

2、select语句所在的Mapper需配置了<cache> 或<cached-ref>节点

3、select语句的参数 useCache=true

Mybatis配置文件如下:

<settings>
	<!-- 这个配置使全局的映射器启用或禁用缓存 -->
   	<setting name="cacheEnabled" value="true" />
   	<!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->
  	<setting name="multipleResultSetsEnabled" value="true"/>
    	<!-- 配置默认的执行器。SIMPLE 执行器没有什么特别之处。REUSE 执行器重用预处理语句。BATCH 执行器重用语句和批量更新 -->
    	<setting name="defaultExecutorType" value="REUSE" />
    	<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 -->
    	<setting name="lazyLoadingEnabled" value="false" />
    	<setting name="aggressiveLazyLoading" value="true" />
   	<!-- <setting name="enhancementEnabled" value="true"/> -->
    	<!-- 设置超时时间,它决定驱动等待一个数据库响应的时间。 -->
    	<setting name="defaultStatementTimeout" value="25000" />
</settings>

 Mybatis的Mapper的配置文件如下:

<?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="user">

	<!-- 二级缓存 -->
	<cache type="com.qunar.mobile.mybatis.cache.QRedisCache"/>

	<select id="getUsers" resultType="User" useCache="true">
		select
			user_id as userId, user_name as username, user_desc as userDesc, create_time as createTime
		from bisystem_user
	</select>

</mapper>

  自定义二级缓存需要实现Mybatis的Cache接口,Redis缓存实现如下:

public class QRedisCache implements Cache {

	private String cacheId;

	private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); 

	public QRedisCache(String cacheId) {
		if (cacheId == null) {
			throw new IllegalArgumentException("Cache instances require an ID");
		}
		this.cacheId = cacheId;
	}

	@Override
	public String getId() {
		return cacheId;
	}

	@Override
	public void putObject(Object key, Object value) {
		JedisUtils.put(key, value);
	}

	@Override
	public Object getObject(Object key) {
		return JedisUtils.get(key);
	}

	@Override
	public Object removeObject(Object key) {
		return JedisUtils.remove(key);
	}

	@Override
	public void clear() {
		JedisUtils.removeAll();
	}

	@Override
	public int getSize() {
		return 0;
	}

	@Override
	public ReadWriteLock getReadWriteLock() {
		return readWriteLock;
	}

}

  在QRedisCache使用的辅助类JedisUtils及SerializeUtils实现如下:

public class JedisUtils {

	private static final Logger logger = Logger.getLogger(JedisUtils.class);

	private static JedisPool JEDISPOOL;

	static {
		Properties props = new Properties();
		try {
			props.load(JedisUtils.class.getResourceAsStream("/redis.properties"));
			JedisPoolConfig conf = new JedisPoolConfig();
			conf.setMaxIdle(Integer.valueOf(props.getProperty("jedis.pool.maxIdle")));
			conf.setTestOnBorrow(Boolean.valueOf(props.getProperty("jedis.pool.testOnBorrow")));
			conf.setTestOnReturn(Boolean.valueOf(props.getProperty("jedis.pool.testOnReturn")));
			JEDISPOOL = new JedisPool(conf, props.getProperty("redis.ip"), Integer.valueOf(props.getProperty("redis.port")));
		} catch (IOException e) {
			logger.error("加载[jedis.properties]异常[" + e.getMessage() + "]", e);
		}
	}

	public static Jedis getJedis() {
		return JEDISPOOL.getResource();
	}

	public static void recycleJedis(Jedis jedis) {
		jedis.close();
	}

	/**
	 * Redis存储Object序列化流
	 * */
	public static void put(Object key, Object value) {
		Jedis jedis = getJedis();
		jedis.set(SerializeUtils.serialize(key), SerializeUtils.serialize(value));
		recycleJedis(jedis);
	}

	public static <T> T get(Object key) {
		Jedis jedis = getJedis();
		T value = SerializeUtils.unserialize(jedis.get(SerializeUtils.serialize(key)));
		recycleJedis(jedis);
		return value;
	}

	public static Long remove(Object key) {
		Jedis jedis = getJedis();
		Long num = jedis.del(SerializeUtils.serialize(key));
		recycleJedis(jedis);
		return num;
	}

	public static void removeAll() {
		Jedis jedis = getJedis();
		jedis.flushDB();
		recycleJedis(jedis);
	}
}

public class SerializeUtils {

	private static final Logger logger = Logger.getLogger(SerializeUtils.class);

	private static void close(ObjectOutputStream objectOutputStream, ByteArrayOutputStream byteArrayOutputStream) {
		try {
			if (byteArrayOutputStream != null) {
				byteArrayOutputStream.close();
			}
			if (objectOutputStream != null) {
				objectOutputStream.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("关闭IO资源异常[" + e.getMessage() + "]", e);
		}
	}

	private static void close(ObjectInputStream objectInputStream, ByteArrayInputStream byteArrayInputStream) {
		try {
			if (objectInputStream != null) {
				objectInputStream.close();
			}
			if (byteArrayInputStream != null) {
				byteArrayInputStream.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("关闭IO资源异常[" + e.getMessage() + "]", e);
		}
	}

	public static byte[] serialize(Object object) {
		ObjectOutputStream objectOutputStream = null;
		ByteArrayOutputStream byteArrayOutputStream = null;
		try {
			byteArrayOutputStream = new ByteArrayOutputStream();
			objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
			objectOutputStream.writeObject(object);
			byte[] bytes = byteArrayOutputStream.toByteArray();
			return bytes;
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("序列化对象异常[" + e.getMessage() + "]", e);
		} finally {
			close(objectOutputStream, byteArrayOutputStream);
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	public static <T> T unserialize(byte[] bytes) {
		if (bytes == null)
			return null;
		ByteArrayInputStream byteArrayInputStream = null;
		ObjectInputStream objectInputStream = null;
		try {
			byteArrayInputStream = new ByteArrayInputStream(bytes);
			objectInputStream = new ObjectInputStream(byteArrayInputStream);
			return (T) objectInputStream.readObject();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			close(objectInputStream, byteArrayInputStream);
		}
		return null;
	}

}

  Redis的配置文件redis.properties如下:

#redis服务器ip#   

redis.ip=192.168.2.107

#redis服务器端口号#  

redis.port=6379

#********jedis池参数设置********#  

#jedis的最大分配对象#  

jedis.pool.maxActive=3000

#jedis最大保存idel状态对象数 #  

jedis.pool.maxIdle=1000

#jedis池没有对象返回时,最大等待时间 #  

jedis.pool.maxWait=1500

#jedis调用borrowObject方法时,是否进行有效检查#  

jedis.pool.testOnBorrow=true

#jedis调用returnObject方法时,是否进行有效检查 #  

jedis.pool.testOnReturn=true

  

 

时间: 2024-11-08 06:51:47

Mybatis使用Redis二级缓存的相关文章

【MyBatis学习13】MyBatis中的二级缓存

1. 二级缓存的原理 前面介绍了,mybatis中的二级缓存是mapper级别的缓存,值得注意的是,不同的mapper都有一个二级缓存,也就是说,不同的mapper之间的二级缓存是互不影响的.为了更加清楚的描述二级缓存,先来看一个示意图: 从图中可以看出: sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到该UserMapper的二级缓存中. 如果SqlSession3去执行相同 mapper下sql,执行commit提交,则会清空该UserMapper下二级缓

Mybatis学习笔记-二级缓存

~ 缓存是提供应用系统性能的重要手段,前面已经介绍过Mybatis是一级缓存,与一级缓存不同的是,二级缓存的作用范围扩大到了应用级别,并且可以比一级缓存更细粒度的对二级缓存的应用进行配置.下面就详细叙述一下Mybatis的二级缓存实现. 二级缓存的工作流程 不多说,先上图,图解是攻城狮最好的朋友^_^- 前面在叙述一级缓存的时候已经说过,一级缓存是一块放在Executor中的map内存块.试想一下,如果二级缓存也是Executor中的内存块可以可以呢?-- 当然不可以!为啥?因为二级缓存要支持细

Mybatis自定义分布式二级缓存实现与遇到的一些问题解决方案!

先说两句: 我们都知道Mybatis缓存分两类: 一级缓存(同一个Session会话内) & 二级缓存(基于HashMap实现的以 namespace为范围的缓存) 今天呢, 我们不谈一级缓存, 我们来谈一谈 二级缓存, 通过查看Mybatis源码发现, 他的二级缓存实现真的十分简单, 默认的实现类是 org.apache.ibatis.cache.impl.PerpetualCache 这里贴一下他的源码吧: /** * Copyright 2009-2015 the original aut

Mybatis一级、二级缓存

一级缓存 首先做一个测试,创建一个mapper配置文件和mapper接口,我这里用了最简单的查询来演示. <mapper namespace="cn.elinzhou.mybatisTest.mapper.UserMapper"> <select id="findUsers" resultType="cn.elinzhou.mybatisTest.pojo.User"> SELECT * FROM user </se

mybatis(4)_二级缓存深入_使用第三方ehcache配置二级缓存

增删改对二级缓存的影响 1.增删改也会清空二级缓存 2.对于二级缓存的清空实质上是对value清空为null,key依然存在,并非将Entry<k,v>删除 3.从DB中进行select查询的条件是: 1.缓存中根本不存在这个key 2.存在key对应的Entry,但是value为null 二级缓存的配置 <cache eviction="FIFO" flushInterval="60000" size="512" readOn

mybatis 学习五 二级缓存不推荐使用

mybatis 二级缓存不推荐使用 一 mybatis的缓存使用. 大体就是首先根据你的sqlid,参数的信息自己算出一个key值,然后你查询的时候,会先把这个key值去缓存中找看有没有value,如果有,直接返回出来,就不查询db了.如果没有,那么查询db,然后将key,value保存到缓存中,以便下次使用. 1.1mybatis的一级缓存是基于sqlsession为生命周期的 当你这个session没有了,缓存就没有了,其次当你sql执行!isselect语句的时候,缓存也会被直接全部清理掉

使用Redis做MyBatis的二级缓存

1. 介绍 使用mybatis时可以使用二级缓存提高查询速度,进而改善用户体验. 使用redis做mybatis的二级缓存可是内存可控<如将单独的服务器部署出来用于二级缓存>,管理方便. 2. 使用思路 2.1 配置redis.xml 设置redis服务连接各参数 2.1 在配置文件中使用 <setting> 标签,设置开启二级缓存: 2.2 在mapper.xml 中使用<cache type="com.demo.RedisCacheClass" /&g

MyBatis系列目录--5. MyBatis一级缓存和二级缓存(redis实现)

转载请注明出处哈:http://carlosfu.iteye.com/blog/2238662 0. 相关知识: 查询缓存:绝大数系统主要是读多写少. 缓存作用:减轻数据库压力,提供访问速度. 1. 一级缓存测试用例 (1) 默认开启,不需要有什么配置 (2) 示意图 (3) 测试代码 Java代码   package com.sohu.tv.cache; import org.apache.ibatis.session.SqlSession; import org.junit.After; i

SpringBoot+Mybatis+redis实现二级缓存

对于查询比较多的项目可以考虑配置二级缓存,mybatis本身的二级缓存是缓存到本地,但是对于多个节点的项目来说,可能会出现数据不一致的问题,所以采用redis缓存,这样二级缓存的数据就可以缓存到内存,可实现多个节点项目的数据同步. 1.配置redis的连接 #redis gmall.redis.host=172.16.1.250 gmall.redis.port=6379 gmall.redis.pass=Gworld2017 gmall.redis.photo.database=6 #最大分配