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>