Browse Source

解决乐观锁在同一事务中第二次调用不处理的问题。
主要是增加对parameterize的拦截,在parameterize的时候再注入version值

tantan 8 years ago
parent
commit
038dfdad4b

+ 36 - 16
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/OptimisticLockerInterceptor.java

@@ -16,8 +16,10 @@
 package com.baomidou.mybatisplus.plugins;
 package com.baomidou.mybatisplus.plugins;
 
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.lang.reflect.Type;
+import java.sql.Statement;
 import java.sql.Timestamp;
 import java.sql.Timestamp;
 import java.util.Date;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashMap;
@@ -29,7 +31,7 @@ import java.util.concurrent.ConcurrentHashMap;
 
 
 import org.apache.ibatis.binding.MapperMethod.ParamMap;
 import org.apache.ibatis.binding.MapperMethod.ParamMap;
 import org.apache.ibatis.exceptions.ExceptionFactory;
 import org.apache.ibatis.exceptions.ExceptionFactory;
-import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.executor.statement.StatementHandler;
 import org.apache.ibatis.mapping.BoundSql;
 import org.apache.ibatis.mapping.BoundSql;
 import org.apache.ibatis.mapping.MappedStatement;
 import org.apache.ibatis.mapping.MappedStatement;
 import org.apache.ibatis.mapping.ParameterMapping;
 import org.apache.ibatis.mapping.ParameterMapping;
@@ -40,6 +42,7 @@ import org.apache.ibatis.plugin.Invocation;
 import org.apache.ibatis.plugin.Plugin;
 import org.apache.ibatis.plugin.Plugin;
 import org.apache.ibatis.plugin.Signature;
 import org.apache.ibatis.plugin.Signature;
 import org.apache.ibatis.reflection.MetaObject;
 import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.SystemMetaObject;
 import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.session.defaults.DefaultSqlSession;
 import org.apache.ibatis.session.defaults.DefaultSqlSession;
 import org.apache.ibatis.type.TypeException;
 import org.apache.ibatis.type.TypeException;
@@ -48,6 +51,7 @@ import org.apache.ibatis.type.UnknownTypeHandler;
 import com.baomidou.mybatisplus.annotations.TableField;
 import com.baomidou.mybatisplus.annotations.TableField;
 import com.baomidou.mybatisplus.annotations.Version;
 import com.baomidou.mybatisplus.annotations.Version;
 import com.baomidou.mybatisplus.mapper.EntityWrapper;
 import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.toolkit.PluginUtils;
 import com.baomidou.mybatisplus.toolkit.StringUtils;
 import com.baomidou.mybatisplus.toolkit.StringUtils;
 
 
 import net.sf.jsqlparser.expression.BinaryExpression;
 import net.sf.jsqlparser.expression.BinaryExpression;
@@ -76,7 +80,8 @@ import net.sf.jsqlparser.statement.update.Update;
  * @since 2017-04-08
  * @since 2017-04-08
  */
  */
 @Intercepts({
 @Intercepts({
-		@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) })
+		@Signature(type = StatementHandler.class, method = "prepare", args = {MappedStatement.class, Object.class}),
+		@Signature(type = StatementHandler.class, method = "parameterize", args = { Statement.class })  })
 public final class OptimisticLockerInterceptor implements Interceptor {
 public final class OptimisticLockerInterceptor implements Interceptor {
 
 
 	/**
 	/**
@@ -105,19 +110,30 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 	}
 	}
 
 
 	public Object intercept(Invocation invocation) throws Exception {
 	public Object intercept(Invocation invocation) throws Exception {
+		//判断是prepare还是parameterize
+		//prepare的时候变更update 条件
+		//parameterize的时候赋值
+		Method m = invocation.getMethod();
+		String methodName ="";
+		if ("prepare".equals(m.getName())) {
+			methodName="prepare";
+		} else if ("parameterize".equals(m.getName())) {
+			methodName="parameterize";
+		}
+		StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
+		MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
 		// 先判断是不是真正的UPDATE操作
 		// 先判断是不是真正的UPDATE操作
-		MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
-		Object parameterObject = invocation.getArgs()[1];
+		MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
 		if (!ms.getSqlCommandType().equals(SqlCommandType.UPDATE)) {
 		if (!ms.getSqlCommandType().equals(SqlCommandType.UPDATE)) {
 			return invocation.proceed();
 			return invocation.proceed();
 		}
 		}
-		BoundSql boundSql = ms.getBoundSql(parameterObject);
+		BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
 		// 获得参数类型,去缓存中快速判断是否有version注解才继续执行
 		// 获得参数类型,去缓存中快速判断是否有version注解才继续执行
 		Class<?> parameterClass = ms.getParameterMap().getType();
 		Class<?> parameterClass = ms.getParameterMap().getType();
 		LockerCache lockerCache = versionCache.get(parameterClass);
 		LockerCache lockerCache = versionCache.get(parameterClass);
 		if (lockerCache != null) {
 		if (lockerCache != null) {
 			if (lockerCache.lock) {
 			if (lockerCache.lock) {
-				processChangeSql(ms, boundSql, lockerCache);
+				processChangeSql(ms, boundSql, lockerCache,methodName);
 			}
 			}
 		} else {
 		} else {
 			Field versionField = getVersionField(parameterClass);
 			Field versionField = getVersionField(parameterClass);
@@ -133,7 +149,7 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 				}
 				}
 				LockerCache lc = new LockerCache(true, versionColumn, versionField, typeHandlers.get(fieldType));
 				LockerCache lc = new LockerCache(true, versionColumn, versionField, typeHandlers.get(fieldType));
 				versionCache.put(parameterClass, lc);
 				versionCache.put(parameterClass, lc);
-				processChangeSql(ms, boundSql, lc);
+				processChangeSql(ms, boundSql, lc,methodName);
 			} else {
 			} else {
 				versionCache.put(parameterClass, LockerCache.INSTANCE);
 				versionCache.put(parameterClass, LockerCache.INSTANCE);
 			}
 			}
@@ -156,7 +172,7 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 
 
 	}
 	}
 
 
-	private void processChangeSql(MappedStatement ms, BoundSql boundSql, LockerCache lockerCache) throws Exception {
+	private void processChangeSql(MappedStatement ms, BoundSql boundSql, LockerCache lockerCache,String methodName) throws Exception {
 		Object parameterObject = boundSql.getParameterObject();
 		Object parameterObject = boundSql.getParameterObject();
 		if (parameterObject instanceof ParamMap) {
 		if (parameterObject instanceof ParamMap) {
 			ParamMap<?> paramMap = (ParamMap<?>) parameterObject;
 			ParamMap<?> paramMap = (ParamMap<?>) parameterObject;
@@ -165,26 +181,25 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 			if (entityWrapper != null) {
 			if (entityWrapper != null) {
 				Object entity = entityWrapper.getEntity();
 				Object entity = entityWrapper.getEntity();
 				if (entity != null && lockerCache.field.get(entity) == null) {
 				if (entity != null && lockerCache.field.get(entity) == null) {
-					changSql(ms, boundSql, parameterObject, lockerCache);
+					changSql(ms, boundSql, parameterObject, lockerCache,methodName);
 				}
 				}
 			}
 			}
 		} else if(!(parameterObject instanceof DefaultSqlSession.StrictMap)) {
 		} else if(!(parameterObject instanceof DefaultSqlSession.StrictMap)) {
 			//如果是有逻辑删,且DELETE传入字段为ID或IDS的话,MYBATIS就会使用StrictMap
 			//如果是有逻辑删,且DELETE传入字段为ID或IDS的话,MYBATIS就会使用StrictMap
 			//这里是判断如量不为ParamMap县城不为StrictMap类型就进行乐观锁
 			//这里是判断如量不为ParamMap县城不为StrictMap类型就进行乐观锁
-			changSql(ms, boundSql, parameterObject, lockerCache);
+			changSql(ms, boundSql, parameterObject, lockerCache,methodName);
 		}
 		}
 	}
 	}
 
 
 	@SuppressWarnings("unchecked")
 	@SuppressWarnings("unchecked")
-	private void changSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, LockerCache lockerCache)
+	private void changSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, LockerCache lockerCache,String methodName)
 			throws Exception {
 			throws Exception {
 		Field versionField = lockerCache.field;
 		Field versionField = lockerCache.field;
 		String versionColumn = lockerCache.column;
 		String versionColumn = lockerCache.column;
 		final Object versionValue = versionField.get(parameterObject);
 		final Object versionValue = versionField.get(parameterObject);
 		if (versionValue != null) {// 先判断传参是否携带version,没带跳过插件
 		if (versionValue != null) {// 先判断传参是否携带version,没带跳过插件
 			Configuration configuration = ms.getConfiguration();
 			Configuration configuration = ms.getConfiguration();
-			// 给字段赋新值
-			lockerCache.versionHandler.plusVersion(parameterObject, versionField, versionValue);
+
 			// 处理where条件,添加?
 			// 处理where条件,添加?
 			Update jsqlSql = (Update) CCJSqlParserUtil.parse(boundSql.getSql());
 			Update jsqlSql = (Update) CCJSqlParserUtil.parse(boundSql.getSql());
 			BinaryExpression expression = (BinaryExpression) jsqlSql.getWhere();
 			BinaryExpression expression = (BinaryExpression) jsqlSql.getWhere();
@@ -199,8 +214,13 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 				boundSqlMeta.setValue("sql", jsqlSql.toString());
 				boundSqlMeta.setValue("sql", jsqlSql.toString());
 				boundSqlMeta.setValue("parameterMappings", parameterMappings);
 				boundSqlMeta.setValue("parameterMappings", parameterMappings);
 			}
 			}
-			// 设置参数
-			boundSql.setAdditionalParameter("originVersionValue", versionValue);
+			//只有parameterize才给字段赋值
+			if("parameterize".equals(methodName)) {
+				// 给字段赋新值
+				lockerCache.versionHandler.plusVersion(parameterObject, versionField, versionValue);
+				// 设置参数
+				boundSql.setAdditionalParameter("originVersionValue", versionValue);
+			}
 		}
 		}
 	}
 	}
 	
 	
@@ -220,7 +240,7 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 
 
 	@Override
 	@Override
 	public Object plugin(Object target) {
 	public Object plugin(Object target) {
-		if (target instanceof Executor) {
+		if (target instanceof StatementHandler) {
 			return Plugin.wrap(target, this);
 			return Plugin.wrap(target, this);
 		}
 		}
 		return target;
 		return target;