
com.jeesuite.mybatis.plugin.cache.CacheHandler Maven / Gradle / Ivy
package com.jeesuite.mybatis.plugin.cache;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.persistence.Id;
import javax.persistence.Table;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jeesuite.mybatis.core.BaseEntity;
import com.jeesuite.mybatis.core.InterceptorHandler;
import com.jeesuite.mybatis.core.InterceptorType;
import com.jeesuite.mybatis.crud.builder.SqlTemplate;
import com.jeesuite.mybatis.kit.CacheKeyUtils;
import com.jeesuite.mybatis.kit.ReflectUtils;
import com.jeesuite.mybatis.parser.EntityInfo;
import com.jeesuite.mybatis.parser.MybatisMapperParser;
import com.jeesuite.mybatis.plugin.JeesuiteMybatisPluginContext;
import com.jeesuite.mybatis.plugin.cache.annotation.Cache;
import com.jeesuite.mybatis.plugin.cache.annotation.CacheEvictCascade;
import com.jeesuite.mybatis.plugin.cache.name.DefaultCacheMethodDefine;
import com.jeesuite.mybatis.plugin.cache.name.Mapper3CacheMethodDefine;
import com.jeesuite.mybatis.plugin.cache.provider.DefaultCacheProvider;
/**
* 自动缓存拦截处理
* @description
* @author vakin
* @date 2015年12月7日
* @Copyright (c) 2015, jwww
*/
public class CacheHandler implements InterceptorHandler {
protected static final Logger logger = LoggerFactory.getLogger(CacheHandler.class);
private static final String ID_CACHEKEY_JOIN = ".id:";
private static final String WHERE_REGEX = "(w|W)(here|HERE)";
private static final String QUERY_IDS_SUFFIX = "_ralateIds";
protected static final String SPLIT_PONIT = ".";
public static final String GROUPKEY_SUFFIX = "~keys";
//需要缓存的所有mapper
private static List cacheEnableMappers = new ArrayList<>();
private static Map mapperNameRalateEntityNames = new HashMap<>();
/**
* 更新方法关联的缓存组
*/
private static Map> cacheEvictCascades = new HashMap<>();
private static Map> queryCacheMethods = new HashMap<>();
private static Map updateCacheMethods = new HashMap<>();
private static List groupKeys = new ArrayList<>();
//记录当前线程写入的所有缓存key
private static ThreadLocal> TransactionWriteCacheKeys = new ThreadLocal<>();
protected static CacheProvider cacheProvider;
private CacheMethodDefine methodDefine;
private ScheduledExecutorService clearExpiredGroupKeysTimer;
public void setCacheProvider(CacheProvider cacheProvider) {
CacheHandler.cacheProvider = cacheProvider;
}
@Override
public Object onInterceptor(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
MappedStatement mt = (MappedStatement)args[0];
if(mt.getSqlCommandType().equals(SqlCommandType.SELECT)){
//按主键查询
QueryMethodCache cacheInfo = getQueryMethodCache(mt.getId());
if(cacheInfo == null)return null;
final String cacheKey = genarateQueryCacheKey(cacheInfo.keyPattern, args[1]);
//按主键查询以及标记非引用关系的缓存直接读取缓存
if(cacheInfo.isSecondQueryById() == false){
//从缓存读取
Object object = cacheProvider.get(cacheKey);
if(object != null){
//mybatis返回都是list,所以这里要包装一下
if(object instanceof List == false){
object = new ArrayList<>(Arrays.asList(object));
}
if(logger.isDebugEnabled())logger.debug("_autocache_ method[{}] find result from cacheKey:{}",mt.getId(),cacheKey);
}
return object;
}else{
//新根据缓存KEY找到与按ID缓存的KEY
String cacheKeyById = cacheProvider.getStr(cacheKey);
if(cacheKeyById == null)return null;
Object object = cacheProvider.get(cacheKeyById);
if(object != null){
object = new ArrayList<>(Arrays.asList(object));
if(logger.isDebugEnabled())logger.debug("_autocache_ method[{}] find result from cacheKey:{} ,ref by:{}",mt.getId(),cacheKeyById,cacheKey);
}
return object;
}
}
return null;
}
@SuppressWarnings("rawtypes")
@Override
public void onFinished(Invocation invocation,Object result) {
Object[] args = invocation.getArgs();
MappedStatement mt = (MappedStatement)args[0];
String mapperNameSpace = mt.getId().substring(0, mt.getId().lastIndexOf(SPLIT_PONIT));
QueryMethodCache cacheInfo = null;
if(mt.getSqlCommandType().equals(SqlCommandType.SELECT)){
if(result == null)return;
if((cacheInfo = getQueryMethodCache(mt.getId())) == null)return;
if(result instanceof List){
List list = (List)result;
if(list.isEmpty())return;
result = cacheInfo.collectionResult ? result : list.get(0);
}
final String cacheKey = genarateQueryCacheKey(cacheInfo.keyPattern, args[1]);
//按主键查询以及标记非引用关系的缓存直接读取缓存
if(cacheInfo.isSecondQueryById() == false){
if(cacheProvider.set(cacheKey,result, cacheInfo.expire)){
if(logger.isDebugEnabled())logger.debug("_autocache_ method[{}] put result to cache,cacheKey:{}",mt.getId(),cacheKey);
}
//结果为集合的情况,增加key到cacheGroup
if(cacheInfo.groupRalated){
cacheProvider.putGroupKeys(cacheInfo.cacheGroupKey, cacheKey,cacheInfo.expire);
logger.debug("_autocache_ method[{}] add key:[{}] to group key:[{}]",mt.getId(),cacheInfo.cacheGroupKey, cacheKey);
}else{
//
cacheUniqueSelectRef(result, mt, cacheKey);
}
}else{
//之前没有按主键的缓存,增加按主键缓存
String idCacheKey = genarateQueryCacheKey(getQueryByPkMethodCache(mt.getId()).keyPattern,result);
if(idCacheKey != null && cacheKey != null && cacheProvider.set(idCacheKey,result, cacheInfo.expire)
&& cacheProvider.set(cacheKey,idCacheKey, cacheInfo.expire)){
if(logger.isDebugEnabled())logger.debug("_autocache_ method[{}] put result to cache,cacheKey:{},and add ref cacheKey:{}",mt.getId(),idCacheKey,cacheKey);
}
}
}else{
if(!cacheEnableMappers.contains(mapperNameSpace))return;
//返回0,未更新成功
if(result != null && ((int)result) == 0)return;
if(updateCacheMethods.containsKey(mt.getId())){
String cacheByPkKey = null;
UpdateByPkMethodCache updateMethodCache = updateCacheMethods.get(mt.getId());
if(updateMethodCache.sqlCommandType.equals(SqlCommandType.DELETE)){
cacheByPkKey = genarateQueryCacheKey(updateMethodCache.keyPattern,args[1]);
cacheProvider.remove(cacheByPkKey);
if(logger.isDebugEnabled())logger.debug("_autocache_ method[{}] remove cacheKey:{} from cache",mt.getId(),cacheByPkKey);
}else{
cacheByPkKey = genarateQueryCacheKey(updateMethodCache.keyPattern,args[1]);
boolean insertCommond = mt.getSqlCommandType().equals(SqlCommandType.INSERT);
if(insertCommond || mt.getSqlCommandType().equals(SqlCommandType.UPDATE)){
if(result != null){
QueryMethodCache queryByPkMethodCache = getQueryByPkMethodCache(mt.getId());
cacheProvider.set(cacheByPkKey,args[1], queryByPkMethodCache.expire);
if(logger.isDebugEnabled())logger.debug("_autocache_ method[{}] update cacheKey:{}",mt.getId(),cacheByPkKey);
//插入其他唯一字段引用
if(insertCommond)cacheUniqueSelectRef(args[1], mt, cacheByPkKey);
//
addCurrentThreadCacheKey(cacheByPkKey);
}
}
}
}else{//按条件删除和更新的情况
Executor executor = (Executor) invocation.getTarget();
removeCacheByUpdateConditon(executor, mt, mapperNameSpace, args);
}
//删除同一cachegroup关联缓存
removeCacheByGroup(mt.getId(), mapperNameSpace);
}
}
/**
* 按更新的查询条件更新缓存
* @param executor
* @param mt
* @param mapperNameSpace
* @param args
*/
private void removeCacheByUpdateConditon(Executor executor, MappedStatement mt, String mapperNameSpace,
Object[] args) {
try {
Object parameterObject = args[1];
EntityInfo entityInfo = MybatisMapperParser.getEntityInfoByMapper(mapperNameSpace);
MappedStatement statement = getQueryIdsMappedStatementForUpdateCache(mt,entityInfo);
List> idsResult = executor.query(statement, parameterObject, RowBounds.DEFAULT, null);
if(idsResult != null){
for (Object id : idsResult) {
String cacheKey = entityInfo.getEntityClass().getSimpleName() + ID_CACHEKEY_JOIN + id.toString();
cacheProvider.remove(cacheKey);
}
if(logger.isDebugEnabled())logger.debug("_autocache_ update Method[{}] executed,remove ralate cache {}.id:[{}]",mt.getId(),entityInfo.getEntityClass().getSimpleName(),idsResult);
}
} catch (Exception e) {
logger.error("_autocache_ update Method[{}] remove ralate cache error",e);
}
}
private MappedStatement getQueryIdsMappedStatementForUpdateCache(MappedStatement mt,EntityInfo entityInfo) {
String msId = mt.getId() + QUERY_IDS_SUFFIX;
MappedStatement statement = null;
Configuration configuration = mt.getConfiguration();
try {
statement = configuration.getMappedStatement(msId);
if(statement != null)return statement;
} catch (Exception e) {}
synchronized (configuration) {
String sql = entityInfo.getMapperSqls().get(mt.getId());
sql = "select "+entityInfo.getIdColumn()+" from "+entityInfo.getTableName()+" WHERE " + sql.split(WHERE_REGEX)[1];
sql = String.format(SqlTemplate.SCRIPT_TEMAPLATE, sql);
SqlSource sqlSource = configuration.getDefaultScriptingLanuageInstance().createSqlSource(configuration, sql, Object.class);
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, msId, sqlSource,SqlCommandType.SELECT);
statementBuilder.resource(mt.getResource());
statementBuilder.fetchSize(mt.getFetchSize());
statementBuilder.statementType(mt.getStatementType());
statementBuilder.parameterMap(mt.getParameterMap());
statement = statementBuilder.build();
List resultMaps = new ArrayList();
String id = msId + "-Inline";
ResultMap.Builder builder = new ResultMap.Builder(configuration, id, entityInfo.getIdType(), new ArrayList(), true);
resultMaps.add(builder.build());
MetaObject metaObject = SystemMetaObject.forObject(statement);
metaObject.setValue("resultMaps", Collections.unmodifiableList(resultMaps));
configuration.addMappedStatement(statement);
return statement;
}
}
/**
* 删除缓存组
* @param mt
* @param mapperNameSpace
*/
private void removeCacheByGroup(String msId, String mapperNameSpace) {
//删除cachegroup关联缓存
String entityName = mapperNameRalateEntityNames.get(mapperNameSpace);
String cacheGroup = entityName + GROUPKEY_SUFFIX;
cacheProvider.clearGroupKeys(cacheGroup);
logger.debug("_autocache_ method[{}] remove cache Group:{}",msId,cacheGroup);
//关联缓存
if(cacheEvictCascades.containsKey(msId)){
for (String entity : cacheEvictCascades.get(msId)) {
cacheGroup = entity + GROUPKEY_SUFFIX;
cacheProvider.clearExpiredGroupKeys(entity + GROUPKEY_SUFFIX);
logger.debug("_autocache_ method[{}] remove Cascade cache Group:[{}]",msId,cacheGroup);
}
}
}
/**
* 缓存其他唯一结果查询方法和主键缓存的引用
* @param object
* @param mt
* @param cacheKey
*/
private void cacheUniqueSelectRef(Object object, MappedStatement mt, String cacheKey) {
Collection mcs = queryCacheMethods.get(mt.getId().substring(0, mt.getId().lastIndexOf(SPLIT_PONIT))).values();
outter:for (QueryMethodCache methodCache : mcs) {
if(methodCache.isPk || methodCache.groupRalated)continue;
try {
Object[] cacheFieldValues = new Object[methodCache.fieldNames.length];
for (int i = 0; i < cacheFieldValues.length; i++) {
if(methodCache.fieldNames[i] == null)continue outter;
cacheFieldValues[i] = ReflectUtils.getObjectValue(object, methodCache.fieldNames[i]);
if(cacheFieldValues[i] == null)continue outter;
}
String fieldCacheKey = genarateQueryCacheKey(methodCache.keyPattern , cacheFieldValues);
cacheProvider.set(fieldCacheKey,cacheKey, methodCache.expire);
if(logger.isDebugEnabled())logger.debug("_autocache_ method[{}] add ref cacheKey:{}",mt.getId(),fieldCacheKey);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 生成查询缓存key
* @param cacheInfo
* @param param
* @return
*/
@SuppressWarnings("unchecked")
private String genarateQueryCacheKey(String keyPattern,Object param){
if(param instanceof Map){
Map map = (Map) param;
Object[] args = new String[map.size()/2];
for (int i = 0; i < args.length; i++) {
args[i] = CacheKeyUtils.toString(map.get("param" + (i+1)));
}
return String.format(keyPattern, args);
}else if(param instanceof BaseEntity){
Serializable id = ((BaseEntity)param).getId();
if(id != null && !"0".equals(id.toString())){
return String.format(keyPattern, ((BaseEntity)param).getId());
}else{
return String.format(keyPattern, CacheKeyUtils.toString(param));
}
}else if(param instanceof Object[]){
return String.format(keyPattern, (Object[])param);
}else{
return param == null ? keyPattern : String.format(keyPattern, CacheKeyUtils.toString(param));
}
}
@Override
public InterceptorType getInterceptorType() {
return InterceptorType.around;
}
private QueryMethodCache getQueryMethodCache(String mtId){
String key1 = mtId.substring(0, mtId.lastIndexOf(SPLIT_PONIT));
if(queryCacheMethods.containsKey(key1)){
return queryCacheMethods.get(key1).get(mtId);
}
return null;
}
private QueryMethodCache getQueryByPkMethodCache(String mtId){
mtId = mtId.substring(0, mtId.lastIndexOf(SPLIT_PONIT));
if(queryCacheMethods.containsKey(mtId)){
return queryCacheMethods.get(mtId).get(mtId + "." + methodDefine.selectName());
}
return null;
}
@Override
public void start(JeesuiteMybatisPluginContext context) {
if("mapper3".equalsIgnoreCase(context.getCrudDriver())){
methodDefine = new Mapper3CacheMethodDefine();
}else{
methodDefine = new DefaultCacheMethodDefine();
}
if(cacheProvider == null)cacheProvider = new DefaultCacheProvider();
List entityInfos = MybatisMapperParser.getEntityInfos();
QueryMethodCache methodCache = null;
for (EntityInfo ei : entityInfos) {
Class> mapperClass = ei.getMapperClass();
//按主键查询方法定义
QueryMethodCache queryByPKMethod = generateQueryByPKMethod(mapperClass, ei.getEntityClass());
if(queryByPKMethod == null)continue;
boolean entityWithAnnotation = ei.getEntityClass().isAnnotationPresent(Cache.class);
Cache annotationCache = null;
String keyPatternForPK = queryByPKMethod.keyPattern;
Map tmpMap = new HashMap<>();
//接口定义的自动缓存方法
Method[] methods = mapperClass.getDeclaredMethods();
for (Method method : methods) {
String fullMethodName = mapperClass.getName() + SPLIT_PONIT + method.getName();
if(method.isAnnotationPresent(Cache.class)){
annotationCache = method.getAnnotation(Cache.class);
if(tmpMap.containsKey(fullMethodName))continue;
methodCache = generateQueryMethodCacheByMethod(mapperClass, ei.getEntityClass(), method);
methodCache.expire = annotationCache.expire();
tmpMap.put(fullMethodName, methodCache);
logger.info("解析查询方法{}自动缓存配置 ok,keyPattern:[{}]",methodCache.methodName,methodCache.keyPattern);
}else if(method.isAnnotationPresent(CacheEvictCascade.class)){
CacheEvictCascade cascade = method.getAnnotation(CacheEvictCascade.class);
if(cascade.cascadeEntities().length > 0){
List entityNames = new ArrayList<>();
for (Class> clazz : cascade.cascadeEntities()) {
entityNames.add(clazz.getSimpleName());
}
cacheEvictCascades.put(fullMethodName, entityNames);
logger.info("解析查询方法{}自动关联更新缓存配置 ok,cascadeEntities:[{}]",fullMethodName,entityNames);
}
}
}
//无任何需要自动缓存的方法
if(entityWithAnnotation == false && tmpMap.isEmpty()){
continue;
}
//selectAll
QueryMethodCache selectAllMethod = generateSelectAllMethod(mapperClass, ei.getEntityClass());
tmpMap.put(selectAllMethod.methodName, selectAllMethod);
//
if(entityWithAnnotation){
queryByPKMethod.expire = ei.getEntityClass().getAnnotation(Cache.class).expire();
selectAllMethod.expire = ei.getEntityClass().getAnnotation(Cache.class).expire();
}
//缓存需要自动缓存的mapper
cacheEnableMappers.add(ei.getMapperClass().getName());
//
mapperNameRalateEntityNames.put(ei.getMapperClass().getName(), ei.getEntityClass().getSimpleName());
//主键查询方法
tmpMap.put(queryByPKMethod.methodName, queryByPKMethod);
logger.info("解析查询方法{}自动缓存配置 ok,keyPattern:[{}]",queryByPKMethod.methodName,queryByPKMethod.keyPattern);
queryCacheMethods.put(mapperClass.getName(), tmpMap);
//更新缓存方法
generateUpdateByPkCacheMethod(mapperClass, ei.getEntityClass(), keyPatternForPK);
//解析方法标注的sql
String sql = null;
for (Method method : methods) {
sql = null;
if(method.isAnnotationPresent(Select.class)){
sql = method.getAnnotation(Select.class).value()[0];
}else if(method.isAnnotationPresent(Update.class)){
sql = method.getAnnotation(Update.class).value()[0];
}else if(method.isAnnotationPresent(Delete.class)){
sql = method.getAnnotation(Delete.class).value()[0];
}
if(sql != null){
String key = ei.getMapperClass().getName() + "." + method.getName();
ei.getMapperSqls().put(key, sql);
}
}
}
//
registerClearExpiredGroupKeyTask();
}
private void registerClearExpiredGroupKeyTask(){
clearExpiredGroupKeysTimer = Executors.newScheduledThreadPool(1);
clearExpiredGroupKeysTimer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
for (String key : groupKeys) {
try {
cacheProvider.clearExpiredGroupKeys(key);
} catch (Exception e) {
logger.warn("_autocache_ clearExpiredGroupKeys for {} error!!",key);
}
}
}
}, 5, 60, TimeUnit.MINUTES);
}
/**
* 生成按主键查询缓存定义
* @param mapperClass
* @param entityClass
* @return
*/
private QueryMethodCache generateQueryByPKMethod(Class> mapperClass,Class> entityClass){
QueryMethodCache methodCache = null;
Field[] fields = entityClass.getDeclaredFields();
//主键key前缀
for (Field field : fields) {
if(field.isAnnotationPresent(Id.class)){
methodCache = new QueryMethodCache();
methodCache.isPk = true;
methodCache.collectionResult = false;
methodCache.keyPattern = entityClass.getSimpleName() + ".id:%s";
methodCache.methodName = mapperClass.getName() + "." + methodDefine.selectName();
methodCache.cacheGroupKey = entityClass.getSimpleName() + GROUPKEY_SUFFIX;
//
groupKeys.add(methodCache.cacheGroupKey);
}
}
return methodCache;
}
private QueryMethodCache generateSelectAllMethod(Class> mapperClass,Class> entityClass){
QueryMethodCache methodCache = new QueryMethodCache();
methodCache.cacheGroupKey = entityClass.getSimpleName() + GROUPKEY_SUFFIX;
methodCache.methodName = mapperClass.getName() + "." + methodDefine.selectAllName();
methodCache.keyPattern = entityClass.getSimpleName() + ".all";
methodCache.isPk = false;
methodCache.collectionResult = true;
methodCache.groupRalated = true;
return methodCache;
}
private void generateUpdateByPkCacheMethod(Class> mapperClass,Class> entityClass,String keyPatternForPK){
String methodName = null;
//按主键插入
String[] insertNames = methodDefine.insertName().split(",");
for (String name : insertNames) {
methodName = mapperClass.getName() + "." + name;
updateCacheMethods.put(methodName, new UpdateByPkMethodCache(entityClass,methodName, keyPatternForPK, SqlCommandType.INSERT));
}
//按主键更新
String[] updateNames = methodDefine.updateName().split(",");
for (String name : updateNames) {
methodName = mapperClass.getName() + "." + name;
updateCacheMethods.put(methodName, new UpdateByPkMethodCache(entityClass,methodName, keyPatternForPK, SqlCommandType.UPDATE));
}
//按主键删除
methodName = mapperClass.getName() + "." + methodDefine.deleteName();
updateCacheMethods.put(methodName, new UpdateByPkMethodCache(entityClass,methodName, keyPatternForPK, SqlCommandType.DELETE));
}
/**
* 按查询方法生成缓存key前缀
* @param entityClassName
* @param method
* @return
*/
private QueryMethodCache generateQueryMethodCacheByMethod(Class> mapperClass,Class> entityClass,Method method){
QueryMethodCache methodCache = new QueryMethodCache();
String methodName = mapperClass.getName() + SPLIT_PONIT + method.getName();
methodCache.methodName = methodName;
methodCache.fieldNames = new String[method.getParameterTypes().length];
methodCache.cacheGroupKey = entityClass.getSimpleName() + GROUPKEY_SUFFIX;
//
methodCache.collectionResult = method.getReturnType() == List.class || method.getReturnType() == Set.class;
if(methodCache.collectionResult){
methodCache.groupRalated = true;
}else{
// count等统计查询
methodCache.groupRalated = method.getReturnType().isAnnotationPresent(Table.class) == false;
}
StringBuilder sb = new StringBuilder(entityClass.getSimpleName()).append(SPLIT_PONIT).append(method.getName());
Annotation[][] annotations = method.getParameterAnnotations();
for (int i = 0; i < annotations.length; i++) {
Annotation[] aa = annotations[i];
if(aa.length > 0){
String fieldName = null;
inner:for (Annotation annotation : aa) {
if(annotation.toString().contains(Param.class.getName())){
fieldName = ((Param)annotation).value();
break inner;
}
}
methodCache.fieldNames[i] = fieldName;
}
//
sb.append(i == 0 ? ":" : "_").append("%s");
}
methodCache.keyPattern = sb.toString();
return methodCache;
}
/**
* 查询缓存方法
*/
private class QueryMethodCache{
public String cacheGroupKey;//缓存组key
public String methodName;
public String keyPattern;
public long expire = CacheExpires.IN_1WEEK;//过期时间(秒)
public boolean isPk = false;//主键查询
public boolean collectionResult = false;//查询结果是集合
public boolean groupRalated = false; //是否需要关联group
public String[] fieldNames;//作为查询条件的字段名称
public QueryMethodCache() {}
/**
* 是否需要通过关联主键二次查询
* @return
*/
public boolean isSecondQueryById(){
return isPk == false && groupRalated == false;
}
}
/**
* 按主键更新(add,update,delete)的方法
*/
private class UpdateByPkMethodCache{
public String keyPattern;
public SqlCommandType sqlCommandType;
public UpdateByPkMethodCache(Class> entityClass,String methodName, String keyPattern, SqlCommandType sqlCommandType) {
this.keyPattern = keyPattern;
this.sqlCommandType = sqlCommandType;
}
}
private void addCurrentThreadCacheKey(String key){
List keys = TransactionWriteCacheKeys.get();
if(keys == null){
keys = new ArrayList<>();
TransactionWriteCacheKeys.set(keys);
}
keys.add(key);
}
/**
* 回滚当前事务写入的缓存
*/
public static void rollbackCache(){
List keys = TransactionWriteCacheKeys.get();
if(keys == null)return;
for (String key : keys) {
cacheProvider.remove(key);
}
}
@Override
public void close() {
try {
cacheProvider.close();
} catch (Exception e) {}
try {
clearExpiredGroupKeysTimer.shutdown();
} catch (Exception e) {}
}
public static void main(String[] args) {
String sql = "select * from user Where id=1";
System.out.println(sql.split(WHERE_REGEX)[1]);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy