spring redis mysql 修改 redis cachekey,增加cachekey的複雜度 。

爲了滿足現有的框架的需求,我將會修改底層框架。


這是Redis 整合spring ,做mysql的緩存,大家沒配的可以照這個來搞搞。


修改底層,出問題,自行負責。


http://blog.csdn.net/u013378306/article/details/52075103

首先,摸清底層框架是怎麼走的,怎麼關聯redis,取值。


都是利用cachekey,來作爲redis的key

這裏底層要求的byte的格式,大家可以自行查看。


/*
 *    Copyright 2009-2014 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.executor;

import static org.apache.ibatis.executor.ExecutionPlaceholder.EXECUTION_PLACEHOLDER;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.cache.impl.PerpetualCache;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.logging.jdbc.ConnectionLogger;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.LocalCacheScope;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.transaction.Transaction;
import org.apache.ibatis.type.TypeHandlerRegistry;

/**
 * @author Clinton Begin
 */
public abstract class BaseExecutor implements Executor {

	private static final Log log = LogFactory.getLog(BaseExecutor.class);

	protected Transaction transaction;
	protected Executor wrapper;

	protected ConcurrentLinkedQueue<DeferredLoad> deferredLoads;
	protected PerpetualCache localCache;
	protected PerpetualCache localOutputParameterCache;
	protected Configuration configuration;

	protected int queryStack = 0;
	private boolean closed;

	protected BaseExecutor(Configuration configuration, Transaction transaction) {
		this.transaction = transaction;
		this.deferredLoads = new ConcurrentLinkedQueue<DeferredLoad>();
		this.localCache = new PerpetualCache("LocalCache");
		this.localOutputParameterCache = new PerpetualCache("LocalOutputParameterCache");
		this.closed = false;
		this.configuration = configuration;
		this.wrapper = this;
	}

	public Transaction getTransaction() {
		if (closed)
			throw new ExecutorException("Executor was closed.");
		return transaction;
	}

	public void close(boolean forceRollback) {
		try {
			try {
				rollback(forceRollback);
			} finally {
				if (transaction != null)
					transaction.close();
			}
		} catch (SQLException e) {
			// Ignore. There's nothing that can be done at this point.
			log.warn("Unexpected exception on closing transaction.  Cause: " + e);
		} finally {
			transaction = null;
			deferredLoads = null;
			localCache = null;
			localOutputParameterCache = null;
			closed = true;
		}
	}

	public boolean isClosed() {
		return closed;
	}

	public int update(MappedStatement ms, Object parameter) throws SQLException {
		ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
		if (closed)
			throw new ExecutorException("Executor was closed.");
		clearLocalCache();
		return doUpdate(ms, parameter);
	}

	public List<BatchResult> flushStatements() throws SQLException {
		return flushStatements(false);
	}

	public List<BatchResult> flushStatements(boolean isRollBack) throws SQLException {
		if (closed)
			throw new ExecutorException("Executor was closed.");
		return doFlushStatements(isRollBack);
	}

	public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)
			throws SQLException {
		BoundSql boundSql = ms.getBoundSql(parameter);
		CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
		return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
	}

	@SuppressWarnings("unchecked")
	public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler,
			CacheKey key, BoundSql boundSql) throws SQLException {
		ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
		if (closed)
			throw new ExecutorException("Executor was closed.");
		if (queryStack == 0 && ms.isFlushCacheRequired()) {
			clearLocalCache();
		}
		List<E> list;
		try {
			queryStack++;
			list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
			if (list != null) {
				handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
			} else {
				list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
			}
		} finally {
			queryStack--;
		}
		if (queryStack == 0) {
			for (DeferredLoad deferredLoad : deferredLoads) {
				deferredLoad.load();
			}
			deferredLoads.clear(); // issue #601
			if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
				clearLocalCache(); // issue #482
			}
		}
		return list;
	}

	public void deferLoad(MappedStatement ms, MetaObject resultObject, String property, CacheKey key,
			Class<?> targetType) {
		if (closed)
			throw new ExecutorException("Executor was closed.");
		DeferredLoad deferredLoad = new DeferredLoad(resultObject, property, key, localCache, configuration,
				targetType);
		if (deferredLoad.canLoad()) {
			deferredLoad.load();
		} else {
			deferredLoads.add(new DeferredLoad(resultObject, property, key, localCache, configuration, targetType));
		}
	}

	/**
	 * 
	 * @author Lyon 創建時間:2016年12月29日 下午4:41:45
	 * @return
	 * @throws Exception
	 */
	public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
		if (closed)
			throw new ExecutorException("Executor was closed.");
		CacheKey cacheKey = new CacheKey();
		cacheKey.update(ms.getId());
		cacheKey.update(rowBounds.getOffset());
		cacheKey.update(rowBounds.getLimit());
		cacheKey.update(boundSql.getSql());
		cacheKey.update(parameterObject.toString()); // 這裏添加我們自己的暗號。。。。,讓cachekey更復雜,因爲之前由於不復雜,導致數據亂套了。
		List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
		TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
		for (int i = 0; i < parameterMappings.size(); i++) { // mimic
																// DefaultParameterHandler
																// logic
			ParameterMapping parameterMapping = parameterMappings.get(i);
			if (parameterMapping.getMode() != ParameterMode.OUT) {
				Object value;
				String propertyName = parameterMapping.getProperty();
				if (boundSql.hasAdditionalParameter(propertyName)) {
					value = boundSql.getAdditionalParameter(propertyName);
				} else if (parameterObject == null) {
					value = null;
				} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
					value = parameterObject;
				} else {
					MetaObject metaObject = configuration.newMetaObject(parameterObject);
					value = metaObject.getValue(propertyName);
				}
				cacheKey.update(value);
			}
		}
		return cacheKey;
	}

	public boolean isCached(MappedStatement ms, CacheKey key) {
		return localCache.getObject(key) != null;
	}

	public void commit(boolean required) throws SQLException {
		if (closed)
			throw new ExecutorException("Cannot commit, transaction is already closed");
		clearLocalCache();
		flushStatements();
		if (required) {
			transaction.commit();
		}
	}

	public void rollback(boolean required) throws SQLException {
		if (!closed) {
			try {
				clearLocalCache();
				flushStatements(true);
			} finally {
				if (required) {
					transaction.rollback();
				}
			}
		}
	}

	public void clearLocalCache() {
		if (!closed) {
			localCache.clear();
			localOutputParameterCache.clear();
		}
	}

	protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException;

	protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException;

	protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds,
			ResultHandler resultHandler, BoundSql boundSql) throws SQLException;

	protected void closeStatement(Statement statement) {
		if (statement != null) {
			try {
				statement.close();
			} catch (SQLException e) {
				// ignore
			}
		}
	}

	private void handleLocallyCachedOutputParameters(MappedStatement ms, CacheKey key, Object parameter,
			BoundSql boundSql) {
		if (ms.getStatementType() == StatementType.CALLABLE) {
			final Object cachedParameter = localOutputParameterCache.getObject(key);
			if (cachedParameter != null && parameter != null) {
				final MetaObject metaCachedParameter = configuration.newMetaObject(cachedParameter);
				final MetaObject metaParameter = configuration.newMetaObject(parameter);
				for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
					if (parameterMapping.getMode() != ParameterMode.IN) {
						final String parameterName = parameterMapping.getProperty();
						final Object cachedValue = metaCachedParameter.getValue(parameterName);
						metaParameter.setValue(parameterName, cachedValue);
					}
				}
			}
		}
	}

	private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds,
			ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
		List<E> list;
		localCache.putObject(key, EXECUTION_PLACEHOLDER);
		try {
			list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
		} finally {
			localCache.removeObject(key);
		}
		localCache.putObject(key, list);
		if (ms.getStatementType() == StatementType.CALLABLE) {
			localOutputParameterCache.putObject(key, parameter);
		}
		return list;
	}

	protected Connection getConnection(Log statementLog) throws SQLException {
		Connection connection = transaction.getConnection();
		if (statementLog.isDebugEnabled()) {
			return ConnectionLogger.newInstance(connection, statementLog, queryStack);
		} else {
			return connection;
		}
	}

	public void setExecutorWrapper(Executor wrapper) {
		this.wrapper = wrapper;
	}

	private static class DeferredLoad {

		private final MetaObject resultObject;
		private final String property;
		private final Class<?> targetType;
		private final CacheKey key;
		private final PerpetualCache localCache;
		private final ObjectFactory objectFactory;
		private final ResultExtractor resultExtractor;

		public DeferredLoad(MetaObject resultObject, String property, CacheKey key, PerpetualCache localCache,
				Configuration configuration, Class<?> targetType) { // issue
																	// #781
			this.resultObject = resultObject;
			this.property = property;
			this.key = key;
			this.localCache = localCache;
			this.objectFactory = configuration.getObjectFactory();
			this.resultExtractor = new ResultExtractor(configuration, objectFactory);
			this.targetType = targetType;
		}

		public boolean canLoad() {
			return localCache.getObject(key) != null && localCache.getObject(key) != EXECUTION_PLACEHOLDER;
		}

		public void load() {
			@SuppressWarnings("unchecked") // we suppose we get back a List
			List<Object> list = (List<Object>) localCache.getObject(key);
			Object value = resultExtractor.extractObjectFromList(list, targetType);
			resultObject.setValue(property, value);
		}

	}

}


自定義的RedisCache


package com.framework.util.redis;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.ibatis.cache.Cache;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

import redis.clients.jedis.exceptions.JedisConnectionException;

/**
 *  
 * @author Lyon
 *
 *創建時間:2016年12月29日 下午3:39:51
 */
public class RedisCache implements Cache  
{  
	public static Logger logger = LogManager.getLogger("RedisCache");
  
    private static JedisConnectionFactory jedisConnectionFactory;  
  
    private final String id;  
  
    /**  
     * The {@code ReadWriteLock}.  
     */  
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();  
  
    public RedisCache(final String id) {  
        if (id == null) {  
            throw new IllegalArgumentException("Cache instances require an ID");  
        }  
        logger.debug("MybatisRedisCache:id=" + id);  
        this.id = id;  
    }  
  
    @Override  
    public void clear()  
    {  
        RedisConnection connection = null;  
        try  
        {  
            connection = jedisConnectionFactory.getConnection();  
            connection.flushDb();  
            connection.flushAll();  
        }  
        catch (JedisConnectionException e)  
        {  
            e.printStackTrace();  
        }  
        finally  
        {  
            if (connection != null) {  
                connection.close();  
            }  
        }  
    }  
  
    @Override  
    public String getId()  
    {  
        return this.id;  
    }  
  
    public Object getObject(Object key)  
    {  
        Object result = null;  
        RedisConnection connection = null; 
        
        try  
        {  
        	if (jedisConnectionFactory==null) {
        		return result;
			}
        	
            connection = jedisConnectionFactory.getConnection();  
            RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();  
            byte[] bytes_key=serializer.serialize(key);
            byte[] redis_key=connection.get(bytes_key);
            result = serializer.deserialize(redis_key);  
        }  
        catch (JedisConnectionException e)  
        {  
            e.printStackTrace();  
        }  
        finally  
        {  
            if (connection != null) {  
                connection.close();  
            }  
        }  
        return result;  
    }  
  
    @Override  
    public ReadWriteLock getReadWriteLock()  
    {  
        return this.readWriteLock;  
    }  
  
    @Override  
    public int getSize()  
    {  
        int result = 0;  
        RedisConnection connection = null;  
        try  
        {  
            connection = jedisConnectionFactory.getConnection();  
            result = Integer.valueOf(connection.dbSize().toString());  
        }  
        catch (JedisConnectionException e)  
        {  
            e.printStackTrace();  
        }  
        finally  
        {  
            if (connection != null) {  
                connection.close();  
            }  
        }  
        return result;  
    }  
  
    @Override  
    public void putObject(Object key, Object value)  
    {  
        RedisConnection connection = null;  
        try  
        {  
        	if (jedisConnectionFactory==null) {
				return ;
			}
            connection = jedisConnectionFactory.getConnection();  
            RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();  
            connection.set(serializer.serialize(key), serializer.serialize(value));  
        }  
        catch (JedisConnectionException e)  
        {  
            e.printStackTrace();  
        }  
        finally  
        {  
            if (connection != null) {  
                connection.close();  
            }  
        }  
    }  
  
    @Override  
    public Object removeObject(Object key)  
    {  
        RedisConnection connection = null;  
        Object result = null;  
        try  
        {  
            connection = jedisConnectionFactory.getConnection();  
            RedisSerializer<Object> serializer = new JdkSerializationRedisSerializer();  
            result =connection.expire(serializer.serialize(key), 0);  
        }  
        catch (JedisConnectionException e)  
        {  
            e.printStackTrace();  
        }  
        finally  
        {  
            if (connection != null) {  
                connection.close();  
            }  
        }  
        return result;  
    }  
  
    public static void setJedisConnectionFactory(JedisConnectionFactory jedisConnectionFactory) {  
        RedisCache.jedisConnectionFactory = jedisConnectionFactory;  
    }

  
}  




發佈了72 篇原創文章 · 獲贊 22 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章