通用魔板

ibatis拦截器

public class SqlMapClientInterceptor implements MethodInterceptor {
    public static final String WRITE="write";
    public static final String READ="read";

    private static Set<String> writeMethods=new HashSet<String>();
    private static Set<String> readMethods=new HashSet<String>();
    private long timeThreshold=200;
    private DataSourceLookupKeyStrategy dataSourceLookupKeyStrategy;
    private LocalConfig localConfig;
    private ConfigService configService;

    static {
        writeMethods.add("insert");
        writeMethods.add("update");
        writeMethods.add("delete");
        readMethods.add("queryForObject");
        readMethods.add("queryForList");
        readMethods.add("queryWithRowHandler");
        readMethods.add("queryForMap");
    }




    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable{
        String methodName = invocation.getMethod().getName();
        boolean isReadMethod=readMethods.contains(methodName);
        boolean isWriteMethod=writeMethods.contains(methodName);
        if(!isReadMethod&&!isWriteMethod){
            return invocation.proceed();
        }
        String operation=READ;
        if(isWriteMethod){
            operation=WRITE;
        }
        String statementName="";
        Object parameters=null;
        Object[] args=invocation.getArguments();
        if(args!=null&&args.length>0){
            if(args[0] instanceof String){
                statementName=(String)args[0];
            }
        }
        if(args!=null&&args.length>1){
            parameters=args[1];
        }

        String room=localConfig.getLocalMachineRoom();
        String dbKey=dataSourceLookupKeyStrategy.lookupCurrentDataSourceKey();
        String dbId=null;
        if(StringUtils.isNotBlank(dbKey)){
            int splittingIndicator=dbKey.lastIndexOf("_");
            if(splittingIndicator!=-1){
                dbId=dbKey.substring(0, splittingIndicator);
            }
        }
        if(StringUtils.isBlank(dbId)){
            String logMsg=logMsg(room,dbKey,methodName,statementName,-1,parameters);
            LogUtil.error(LogUtil.DB_LOG,logMsg);
            throw new IllegalAccessException(logMsg);
        }
        Object result=null;
        long startStamp=System.currentTimeMillis();
        try {
            result=invocation.proceed();
            return result;
        }catch (DuplicateKeyException dke){
            String msg=logMsg(room,dbKey,methodName,statementName,-1,parameters);
            LogUtil.error(LogUtil.DB_LOG,msg,dke);
            throw dke;
        }catch (Throwable e) {
            String msg=logMsg(room,dbKey,methodName,statementName,-1,parameters);
            LogUtil.error(LogUtil.DB_LOG,msg,e);
            throw e;
        }finally {
            long consumedTime=System.currentTimeMillis()-startStamp;
            if(consumedTime>=timeThreshold){
                String msg=logMsg(room,dbKey,methodName,statementName,consumedTime,parameters);
                LogUtil.error(LogUtil.DB_LOG,msg);
            }
        }
    }


    private String logMsg(String room,String dbKey,String method,String statementName,long consumedTime,Object parameters){
        StringBuilder msgBuilder=new StringBuilder();
        if(consumedTime>=timeThreshold){
            msgBuilder.append("DB Slow: Room=");
            msgBuilder.append(room).append(", DB=").append(dbKey).append(", Method=").append(method).append(", Sql=").append(statementName);
            msgBuilder.append(", Consumed=").append(consumedTime).append("ms. Args: ");
        }else{
            msgBuilder.append("DB Error: Room=");
            msgBuilder.append(room).append(", DB=").append(dbKey).append(", Method=").append(method).append(", Sql=").append(statementName);
            msgBuilder.append(". Args:");
        }
        if(parameters==null){
            msgBuilder.append("IS Null");
        }else if(parameters instanceof Map){
            Map<String,Object> paramMap=(Map<String,Object>)parameters;
            if(paramMap.size()==0){
                msgBuilder.append("Is Empty.");
            }else{
                msgBuilder.append(paramMap.toString());
            }
        }else{
            msgBuilder.append(JsonIgnoreAnnotationUtils.writeValueNonull(parameters));
        }

        return msgBuilder.toString();
    }
    

    public void setTimeThreshold(long timeThreshold) {
        this.timeThreshold = timeThreshold;
    }

    public void setDataSourceLookupKeyStrategy(DataSourceLookupKeyStrategy dataSourceLookupKeyStrategy) {
        this.dataSourceLookupKeyStrategy = dataSourceLookupKeyStrategy;
    }
    public void setLocalConfig(LocalConfig localConfig) {
        this.localConfig = localConfig;
    }
    public void setConfigService(ConfigService configService) {
        this.configService = configService;
    }
}

db操作模板

/**
 * 从数据库和缓存中获取
 * 
 * @author 
 *
 * @param <T>
 */
public abstract class GetEntityByDBCacheTemplate<T, K> {

	/**
	 * 最大重试次数
	 */
	private int maxRetryTime = 2;

	/**
	 * 锁定时间
	 */
	private int lockExp = 2;

	private RedisAccess redisAccessLock;

	public GetEntityByDBCacheTemplate(RedisAccess redisAccessLock) {
		this.redisAccessLock = redisAccessLock;
	}

	/**
	 * 从缓存中获取
	 * 
	 * @return
	 */
	public abstract T getEntityFromCache();

	/**
	 * 设置到缓存
	 * 
	 * @param entity
	 */
	public abstract void setEntityToCache(T entity);

	/**
	 * 从数据库中获取
	 * 
	 * @return
	 */
	public abstract T getEntityFromDb();

	/**
	 * 根据业务对象存取类型,获取实体对象
	 * 
	 * @param businessObjectAccessType
	 *            业务对象存取类型
	 * @param cacheObjectType
	 *            缓存对象类型
	 * @param key
	 *            缓存Key
	 * @return
	 */
	public T getEntity(String businessObjectAccessType, CacheObjectType cacheObjectType, K key) {
		/** 如果是缓存模式,直接取缓存 */
		if (businessObjectAccessType.equals(DataAcessConfig.BUSINESS_OBJECT_ACCESS_TYPE_CACHE)) {
			return getEntityFromCache();
		}
		/** 如果是数据库模式,直接取数据库 */
		if (businessObjectAccessType.equals(DataAcessConfig.BUSINESS_OBJECT_ACCESS_TYPE_DB)) {
			return getEntityFromDb();
		}
		/** 其它配置都是缓存+数据库模式 */
		return getEntityAndSetCache(cacheObjectType, key);
	}

	/**
	 * 先取缓存,缓存没有再取库
	 * 
	 * @param cacheObjectType
	 * @param key
	 * @return
	 */
	private T getEntityAndSetCache(CacheObjectType cacheObjectType, K key) {
		// 从缓存中取
		T entity = getEntityFromCache();
		if (entity != null) {
			return entity;
		}
		// 根据来源判断是否同步缓存
		boolean syncCache = true;
		String notSyncCacheInterface = SwitchConfigUtils.getMiddleWareConfig().getNotSyncCacheInterface();
		String interfaceMethod = AccessOperation.getInterfaceMethod();

		if(SwitchConfigUtils.getMiddleWareConfig().isPrintCacheLog()){
			LogUtil.error(LogUtil.UPDATE_EXPORT_SERVICE_LOG, String.format("getEntityAndSetCache syncCache source, configInterface = %s, filterInterface = %s", notSyncCacheInterface, interfaceMethod));
		}

		if(StringUtils.isNotBlank(notSyncCacheInterface) && StringUtils.isNotBlank(interfaceMethod)){
			List<String> notSyncInterfaceList = Arrays.asList(notSyncCacheInterface.split(","));
			if(notSyncInterfaceList.contains(interfaceMethod)){
				if(SwitchConfigUtils.getMiddleWareConfig().isPrintCacheLog()){
					LogUtil.error(LogUtil.UPDATE_EXPORT_SERVICE_LOG, String.format("getEntityAndSetCache syncCache source, interfaceMethod = %s", interfaceMethod));
				}
				UMPUtil.heartMonitor("nosyncCache." + interfaceMethod);
				syncCache = false;
			}
		}

		String lockKey = genKey(cacheObjectType, key) + ".lock";
		lockKey = DigestUtils.md5Hex(lockKey);
		int retryTimes=0;
		for (; retryTimes<maxRetryTime; retryTimes++) {
			int lockResult=RedisKeyUtil.lockAdd(lockKey, lockExp,redisAccessLock);
			if (lockResult==1) {
				if(retryTimes>0){// 再次从缓存中取
					entity = getEntityFromCache();
				}
				if (entity != null) {
					LogUtil.debug(LogUtil.REDIS_LOG,Thread.currentThread().getName()+" Get Cache, Prefix="+cacheObjectType.getPrefix()+" Key="+key);
					RedisKeyUtil.deleteLock(lockKey,redisAccessLock);
					return entity;
				} else {
					entity = getEntityFromDb();
					if (entity != null) {
						if(syncCache){
							setEntityToCache(entity);
						}
					}
					RedisKeyUtil.deleteLock(lockKey,redisAccessLock);
					return entity;
				}
			}else if(lockResult==-1){
				return getEntityFromDb();
			} else if(lockResult==0) {
				try {
					LogUtil.debug(LogUtil.REDIS_LOG,Thread.currentThread().getName()+" Waiting To Get Cache, Prefix="+cacheObjectType.getPrefix()+" Key="+key);
					if(retryTimes<maxRetryTime-1){
						Thread.sleep(20); // 2*100=200
					}
				} catch (InterruptedException e) {
					LogUtil.debug(LogUtil.REDIS_LOG, Thread.currentThread().getName() + " Waiting To Get Cache Error, Prefix=" + cacheObjectType.getPrefix() + " Key=" + key);
				}
			}
		}

		if (retryTimes==maxRetryTime) {
			// 重试都失败则直接操作库设置缓存
			RedisKeyUtil.deleteLock(lockKey,redisAccessLock);
			LogUtil.debug(LogUtil.REDIS_LOG, Thread.currentThread().getName() + " Try Again To Get Cache Error, Prefix=" + cacheObjectType.getPrefix() + " Key=" + key + " Times=" + retryTimes);
		}
		entity = getEntityFromDb();
		if (entity != null) {
			if(syncCache){
				setEntityToCache(entity);
			}
		}

		return entity;
	}

	/**
	 * 生成key
	 *
	 * @param cacheKeyPrefix
	 * @param key
	 * @return
	 */
	private String genKey(CacheObjectType cacheKeyPrefix, K key) {
		if (key == null) {
			throw new IllegalArgumentException("keys isEmpty!!!");
		}
		String entireKey = cacheKeyPrefix.getPrefix() + key.toString();
		return entireKey;
	}



}

redis加锁模板

public abstract class RedisLockTemplate<T> {
    private RedisAccess lockRedisAccess;
    private int retryNumber;
    private long sleepTime;


    /**
     * Redis锁操作模板
     * @param lockRedisAccess 执行锁操作的Redis
     * @param retryNumber 重试次数
     * @param sleepTime 重试等待时间(毫秒)
     */
    public RedisLockTemplate(RedisAccess lockRedisAccess, int retryNumber, long sleepTime) {
        this.lockRedisAccess = lockRedisAccess;
        this.retryNumber = retryNumber;
        this.sleepTime = sleepTime;
    }

    /**
     * 需要进行锁操作的任务
     * @return
     */
    public abstract T processWithLock();


    /**
     * 执行锁操作
     * @param lockKey 被锁定的key
     * @param lockExpire 锁定过期时间
     * @param useLock 是否锁定,主要用于Redis降级
     * @return
     */
    public T execute(String lockKey, int lockExpire,boolean useLock){
        if(!useLock){
            return processWithLock();
        }
        for (int retryCount = 0; retryCount < retryNumber; retryCount++) {
            int lockResult=RedisKeyUtil.lockAdd(lockKey, lockExpire,lockRedisAccess);
            if (lockResult==1) {
                T result= processWithLock();
                RedisKeyUtil.deleteLock(lockKey,lockRedisAccess);
                return result;
            }else if(lockResult==-1){
                T result= processWithLock();
                return result;
            } else {
                try {
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
                    LogUtil.debug(LogUtil.REDIS_LOG, Thread.currentThread().getName() + " Waiting To Lock Key Error, Key=" + lockKey);
                }
            }
        }
        RedisKeyUtil.deleteLock(lockKey,lockRedisAccess);
        return null;
    }

}

mybatis.xml 设置

<bean id="sqlMapClientInterceptor" class="com.jd.user.sdk.dao.route.SqlMapClientInterceptor">
    </bean>
    <bean id="sqlMapClientBeanNameAutoProxyCreator"
          class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="proxyTargetClass" value="true"/>
        <property name="beanNames">
            <list>
                <value>mysqlTemplate</value>
                <value>blackWordJdbcTemplate</value>
            </list>
        </property>
        <property name="interceptorNames">
            <list>
                <value>sqlMapClientInterceptor</value>
            </list>
        </property>
    </bean>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值