標籤:
在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 createTimefrom 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;}@Overridepublic String getId() {return cacheId;}@Overridepublic void putObject(Object key, Object value) {JedisUtils.put(key, value);}@Overridepublic Object getObject(Object key) {return JedisUtils.get(key);}@Overridepublic Object removeObject(Object key) {return JedisUtils.remove(key);}@Overridepublic void clear() {JedisUtils.removeAll();}@Overridepublic int getSize() {return 0;}@Overridepublic 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
Mybatis使用Redis二級緩衝