Browse Source

Merge branch 'dev' of git.oschina.net:baomidou/mybatis-plus into dev

Caratacus 8 năm trước cách đây
mục cha
commit
d53858706c
18 tập tin đã thay đổi với 712 bổ sung157 xóa
  1. 15 0
      mybatis-plus/pom.xml
  2. 3 3
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/AutoSqlInjector.java
  3. 92 124
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/OptimisticLockerInterceptor.java
  4. 4 3
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/PerformanceInterceptor.java
  5. 146 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/H2UserTest.java
  6. 41 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/config/DBConfig.java
  7. 54 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/config/MybatisPlusConfig.java
  8. 16 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/mapper/H2UserMapper.java
  9. 172 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/persistent/H2User.java
  10. 31 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/service/IH2UserService.java
  11. 36 0
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/service/impl/H2UserServiceImpl.java
  12. 2 2
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/plugins/optimisticLocker/CreateDB.sql
  13. 63 19
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/plugins/optimisticLocker/OptimisticLockerInterceptorTest.java
  14. 6 5
      mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/plugins/optimisticLocker/entity/StringVersionUser.java
  15. 12 0
      mybatis-plus/src/test/resources/h2/spring-test-h2.xml
  16. 12 0
      mybatis-plus/src/test/resources/h2/user.ddl.sql
  17. 5 0
      mybatis-plus/src/test/resources/h2/user.insert.sql
  18. 2 1
      mybatis-plus/src/test/resources/plugins/optimisticLockerInterceptor.xml

+ 15 - 0
mybatis-plus/pom.xml

@@ -53,6 +53,7 @@
 		<mybatis-ehcache.version>1.1.0</mybatis-ehcache.version>
 		<junit.version>4.12</junit.version>
 		<velocity.version>1.7</velocity.version>
+		<h2.version>1.4.194</h2.version>
 	</properties>
 
 	<dependencies>
@@ -217,6 +218,12 @@
 			<version>${postgresql.version}</version>
 			<scope>test</scope>
 		</dependency>
+		<dependency>
+			<groupId>com.h2database</groupId>
+			<artifactId>h2</artifactId>
+			<version>${h2.version}</version>
+			<scope>test</scope>
+		</dependency>
 		<!-- test end -->
 	</dependencies>
 
@@ -236,6 +243,14 @@
 					</execution>
 				</executions>
 			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>1.7</source>
+					<target>1.7</target>
+				</configuration>
+			</plugin>
 		</plugins>
 	</build>
 	<!-- 发版时注释END -->

+ 3 - 3
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/AutoSqlInjector.java

@@ -731,11 +731,11 @@ public class AutoSqlInjector implements ISqlInjector {
 	 *            字段信息
 	 * @param prefix
 	 *            条件前缀
-	 * @param colse
+	 * @param close
 	 *            是否闭合标签
 	 * @return
 	 */
-	protected String convertIfTag(boolean ignored, TableFieldInfo fieldInfo, String prefix, boolean colse) {
+	protected String convertIfTag(boolean ignored, TableFieldInfo fieldInfo, String prefix, boolean close) {
 		/* 忽略策略 */
 		FieldStrategy fieldStrategy = fieldInfo.getFieldStrategy();
 		if (fieldStrategy == FieldStrategy.IGNORED) {
@@ -747,7 +747,7 @@ public class AutoSqlInjector implements ISqlInjector {
 		}
 
 		// 关闭标签
-		if (colse) {
+		if (close) {
 			return "</if>";
 		}
 

+ 92 - 124
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/OptimisticLockerInterceptor.java

@@ -3,43 +3,43 @@ package com.baomidou.mybatisplus.plugins;
 import java.lang.reflect.Field;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.sql.Connection;
 import java.sql.Timestamp;
-import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.ibatis.binding.MapperMethod.ParamMap;
 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.MappedStatement;
 import org.apache.ibatis.mapping.ParameterMapping;
 import org.apache.ibatis.mapping.SqlCommandType;
-import org.apache.ibatis.mapping.SqlSource;
 import org.apache.ibatis.plugin.Interceptor;
 import org.apache.ibatis.plugin.Intercepts;
 import org.apache.ibatis.plugin.Invocation;
 import org.apache.ibatis.plugin.Plugin;
 import org.apache.ibatis.plugin.Signature;
 import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.reflection.SystemMetaObject;
 import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.type.TypeException;
 import org.apache.ibatis.type.UnknownTypeHandler;
 
-import com.baomidou.mybatisplus.annotations.TableName;
+import com.baomidou.mybatisplus.annotations.TableField;
 import com.baomidou.mybatisplus.annotations.Version;
 import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.toolkit.PluginUtils;
 import com.baomidou.mybatisplus.toolkit.StringUtils;
 
+import net.sf.jsqlparser.JSQLParserException;
 import net.sf.jsqlparser.expression.BinaryExpression;
 import net.sf.jsqlparser.expression.Expression;
-import net.sf.jsqlparser.expression.JdbcParameter;
 import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
 import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
 import net.sf.jsqlparser.parser.CCJSqlParserUtil;
@@ -48,6 +48,7 @@ import net.sf.jsqlparser.statement.update.Update;
 
 /**
  * MyBatis乐观锁插件
+ * <p>
  * 
  * <pre>
  * 之前:update user set name = ?, password = ? where id = ?
@@ -57,16 +58,16 @@ import net.sf.jsqlparser.statement.update.Update;
  * 支持short,Short,int Integer, long Long, Date Timestamp
  * 其他类型可以自定义实现,注入versionHandlers,多个以逗号分隔
  * </pre>
- * 
+ *
  * @author TaoYu
  */
-@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
+@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
 public final class OptimisticLockerInterceptor implements Interceptor {
 
 	/**
 	 * 根据对象类型缓存version基本信息
 	 */
-	private static final Map<Class<?>, VersionCache> versionCache = new ConcurrentHashMap<Class<?>, VersionCache>();
+	private static final Map<Class<?>, CachePo> versionCache = new ConcurrentHashMap<Class<?>, CachePo>();
 
 	/**
 	 * 根据version字段类型缓存的处理器
@@ -74,55 +75,50 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 	private static final Map<Class<?>, VersionHandler<?>> typeHandlers = new HashMap<Class<?>, VersionHandler<?>>();
 
 	static {
-		ShortTypeHnadler shortTypeHnadler = new ShortTypeHnadler();
-		typeHandlers.put(short.class, shortTypeHnadler);
-		typeHandlers.put(Short.class, shortTypeHnadler);
+		ShortTypeHandler shortTypeHandler = new ShortTypeHandler();
+		typeHandlers.put(short.class, shortTypeHandler);
+		typeHandlers.put(Short.class, shortTypeHandler);
 
-		IntegerTypeHnadler integerTypeHnadler = new IntegerTypeHnadler();
-		typeHandlers.put(int.class, integerTypeHnadler);
-		typeHandlers.put(Integer.class, integerTypeHnadler);
+		IntegerTypeHandler integerTypeHandler = new IntegerTypeHandler();
+		typeHandlers.put(int.class, integerTypeHandler);
+		typeHandlers.put(Integer.class, integerTypeHandler);
 
-		LongTypeHnadler longTypeHnadler = new LongTypeHnadler();
-		typeHandlers.put(long.class, longTypeHnadler);
-		typeHandlers.put(Long.class, longTypeHnadler);
+		LongTypeHandler longTypeHandler = new LongTypeHandler();
+		typeHandlers.put(long.class, longTypeHandler);
+		typeHandlers.put(Long.class, longTypeHandler);
 
 		typeHandlers.put(Date.class, new DateTypeHandler());
 		typeHandlers.put(Timestamp.class, new TimestampTypeHandler());
 	}
 
 	public Object intercept(Invocation invocation) throws Exception {
+		StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
+		MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
 		// 先判断入参为null或者不是真正的UPDATE语句
-		MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
-		Object parameterObject = invocation.getArgs()[1];
-		if (parameterObject == null || !ms.getSqlCommandType().equals(SqlCommandType.UPDATE)) {
+		MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
+		if (!ms.getSqlCommandType().equals(SqlCommandType.UPDATE)) {
 			return invocation.proceed();
 		}
+		BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
 		// 获得参数类型,去缓存中快速判断是否有version注解才继续执行
-		Class<? extends Object> parameterClass = parameterObject.getClass();
-		Class<?> realClass = ms.getParameterMap().getType();
-		;
-		Object realParameterObject = parameterObject;
-		if (parameterObject instanceof ParamMap) {
-			EntityWrapper<?> tt = (EntityWrapper<?>) ((ParamMap<?>) parameterObject).get("ew");
-			realParameterObject = tt.getEntity();
-		}
-		VersionCache versionPo = versionCache.get(realClass);
+		Class<?> parameterClass = ms.getParameterMap().getType();
+		CachePo versionPo = versionCache.get(parameterClass);
 		if (versionPo != null) {
 			if (versionPo.isVersionControl) {
-				return processChangeSql(ms, parameterObject, realParameterObject, versionPo, invocation);
+				processChangeSql(ms, boundSql, versionPo);
 			}
 		} else {
 			String versionColumn = null;
 			Field versionField = null;
-			for (final Field field : realClass.getDeclaredFields()) {
+			for (final Field field : parameterClass.getDeclaredFields()) {
 				if (field.isAnnotationPresent(Version.class)) {
 					if (!typeHandlers.containsKey(field.getType())) {
 						throw new TypeException("乐观锁不支持" + field.getType().getName() + "类型,请自定义实现");
 					}
 					versionField = field;
-					final TableName tableName = field.getAnnotation(TableName.class);
-					if (tableName != null) {
-						versionColumn = tableName.value();
+					final TableField tableField = field.getAnnotation(TableField.class);
+					if (tableField != null) {
+						versionColumn = tableField.value();
 					} else {
 						versionColumn = field.getName();
 					}
@@ -131,77 +127,69 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 			}
 			if (versionField != null) {
 				versionField.setAccessible(true);
-				VersionCache cachePo = new VersionCache(true, versionColumn, versionField);
+				CachePo cachePo = new CachePo(true, versionColumn, versionField);
 				versionCache.put(parameterClass, cachePo);
-				return processChangeSql(ms, parameterObject, realParameterObject, cachePo, invocation);
+				processChangeSql(ms, boundSql, cachePo);
 			} else {
-				versionCache.put(parameterClass, new VersionCache(false));
+				versionCache.put(parameterClass, new CachePo(false));
 			}
 		}
 		return invocation.proceed();
 
 	}
 
-	private static final Expression JDBCPARAMETER = new JdbcParameter();
 	private static final Expression RIGHTEXPRESSION = new Column("?");
 
-	@SuppressWarnings({ "rawtypes", "unchecked" })
-	private Object processChangeSql(MappedStatement ms, Object parameterObject, Object realParameterObject, VersionCache versionPo, Invocation invocation) throws Exception {
-		Field versionField = versionPo.versionField;
-		String versionColumn = versionPo.versionColumn;
-		final Object versionValue = versionField.get(realParameterObject);
-		if (versionValue != null) {// 先判断传参是否携带version,没带跳过插件
-			Configuration configuration = ms.getConfiguration();
-			BoundSql originBoundSql = ms.getBoundSql(parameterObject);
-			SqlSource originSqlSource = ms.getSqlSource();
-			MetaObject metaObject = configuration.newMetaObject(ms);
-			try {
-				// 处理
-				Update jsqlSql = (Update) CCJSqlParserUtil.parse(originBoundSql.getSql());
-				List<Column> columns = jsqlSql.getColumns();
-				List<String> columnNames = new ArrayList<String>();
-				for (Column column : columns) {
-					columnNames.add(column.getColumnName());
-				}
-				List<Expression> expressions = jsqlSql.getExpressions();
-				if (!columnNames.contains(versionColumn)) {
-					columns.add(new Column(versionColumn));
-					jsqlSql.setColumns(columns);
-					expressions.add(JDBCPARAMETER);
-					jsqlSql.setExpressions(expressions);
-				}
-				// 处理where条件,添加?
-				BinaryExpression expression = (BinaryExpression) jsqlSql.getWhere();
-				if (expression != null && !expression.toString().contains(versionColumn)) {
-					EqualsTo equalsTo = new EqualsTo();
-					equalsTo.setLeftExpression(new Column(versionColumn));
-					equalsTo.setRightExpression(RIGHTEXPRESSION);
-					jsqlSql.setWhere(new AndExpression(equalsTo, expression));
+	private void processChangeSql(MappedStatement ms, BoundSql boundSql, CachePo cachePo) throws Exception {
+		Field versionField = cachePo.versionField;
+		String versionColumn = cachePo.versionColumn;
+		Object parameterObject = boundSql.getParameterObject();
+		if (parameterObject instanceof ParamMap) {
+			ParamMap<?> paramMap = (ParamMap<?>) parameterObject;
+			parameterObject = paramMap.get("et");
+			EntityWrapper<?> entityWrapper = (EntityWrapper<?>) paramMap.get("ew");
+			if (entityWrapper != null) {
+				Object entity = entityWrapper.getEntity();
+				if (entity != null && versionField.get(entity) == null) {
+					changSql(ms, boundSql, versionField, versionColumn, parameterObject);
 				}
-				// 给字段赋新值
-				VersionHandler targetHandler = typeHandlers.get(versionField.getType());
-				targetHandler.plusVersion(realParameterObject, versionField, versionValue);
-				// 设置sqlSource
-				List<ParameterMapping> parameterMappings = new LinkedList<ParameterMapping>(originBoundSql.getParameterMappings());
-				parameterMappings.add(expressions.size(), createVersionMapping(configuration));
-				Map<String, Object> additionalParameters = new HashMap<String, Object>();
-				additionalParameters.put("originVersionValue", versionValue);
-				SqlSource sqlSource = new OptimisticLockerSqlSource(configuration, jsqlSql.toString(), parameterMappings, additionalParameters);
-				metaObject.setValue("sqlSource", sqlSource);
-				return invocation.proceed();
-			} catch (Exception e) {
-				throw ExceptionFactory.wrapException("乐观锁插件执行失败", e);
-			} finally {
-				metaObject.setValue("sqlSource", originSqlSource);
 			}
+		} else {
+			changSql(ms, boundSql, versionField, versionColumn, parameterObject);
+		}
+	}
 
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	private void changSql(MappedStatement ms, BoundSql boundSql, Field versionField, String versionColumn, Object parameterObject)
+			throws IllegalAccessException, Exception, JSQLParserException {
+		final Object versionValue = versionField.get(parameterObject);
+		if (versionValue != null) {// 先判断传参是否携带version,没带跳过插件
+			Configuration configuration = ms.getConfiguration();
+			// 给字段赋新值
+			VersionHandler targetHandler = typeHandlers.get(versionField.getType());
+			targetHandler.plusVersion(parameterObject, versionField, versionValue);
+			// 处理where条件,添加?
+			Update jsqlSql = (Update) CCJSqlParserUtil.parse(boundSql.getSql());
+			BinaryExpression expression = (BinaryExpression) jsqlSql.getWhere();
+			if (expression != null && !expression.toString().contains(versionColumn)) {
+				EqualsTo equalsTo = new EqualsTo();
+				equalsTo.setLeftExpression(new Column(versionColumn));
+				equalsTo.setRightExpression(RIGHTEXPRESSION);
+				jsqlSql.setWhere(new AndExpression(equalsTo, expression));
+				List<ParameterMapping> parameterMappings = new LinkedList<ParameterMapping>(boundSql.getParameterMappings());
+				parameterMappings.add(jsqlSql.getExpressions().size(), getVersionMappingInstance(configuration));
+				MetaObject boundSqlMeta = configuration.newMetaObject(boundSql);
+				boundSqlMeta.setValue("sql", jsqlSql.toString());
+				boundSqlMeta.setValue("parameterMappings", parameterMappings);
+			}
+			// 设置参数
+			boundSql.setAdditionalParameter("originVersionValue", versionValue);
 		}
-		return invocation.proceed();
 	}
 
-	private ParameterMapping parameterMapping;
+	private volatile ParameterMapping parameterMapping;
 
-	private ParameterMapping createVersionMapping(Configuration configuration) {
+	private ParameterMapping getVersionMappingInstance(Configuration configuration) {
 		if (parameterMapping == null) {
 			synchronized (OptimisticLockerInterceptor.class) {
 				if (parameterMapping == null) {
@@ -212,13 +200,15 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 		return parameterMapping;
 	}
 
+	@Override
 	public Object plugin(Object target) {
-		if (target instanceof Executor) {
+		if (target instanceof StatementHandler) {
 			return Plugin.wrap(target, this);
 		}
 		return target;
 	}
 
+	@Override
 	public void setProperties(Properties properties) {
 		String versionHandlers = properties.getProperty("versionHandlers");
 		if (StringUtils.isNotEmpty(versionHandlers)) {
@@ -247,7 +237,7 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 	/**
 	 * 缓存对象
 	 */
-	private class VersionCache {
+	private class CachePo {
 
 		private Boolean isVersionControl;
 
@@ -255,60 +245,36 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 
 		private Field versionField;
 
-		public VersionCache(Boolean isVersionControl) {
+		public CachePo(Boolean isVersionControl) {
 			this.isVersionControl = isVersionControl;
 		}
 
-		public VersionCache(Boolean isVersionControl, String versionColumn, Field versionField) {
+		public CachePo(Boolean isVersionControl, String versionColumn, Field versionField) {
 			this.isVersionControl = isVersionControl;
 			this.versionColumn = versionColumn;
 			this.versionField = versionField;
 		}
-	}
-
-	/**
-	 * 乐观锁数据源,主要是为动态参数设计
-	 */
-	private class OptimisticLockerSqlSource implements SqlSource {
-
-		private Configuration configuration;
-		private String sql;
-		private List<ParameterMapping> parameterMappings;
-		private Map<String, Object> additionalParameters;
-
-		public OptimisticLockerSqlSource(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Map<String, Object> additionalParameters) {
-			this.configuration = configuration;
-			this.sql = sql;
-			this.parameterMappings = parameterMappings;
-			this.additionalParameters = additionalParameters;
-		}
-
-		public BoundSql getBoundSql(Object parameterObject) {
-			BoundSql boundSql = new BoundSql(configuration, sql, parameterMappings, parameterObject);
-			if (additionalParameters != null && additionalParameters.size() > 0) {
-				for (Entry<String, Object> item : additionalParameters.entrySet()) {
-					boundSql.setAdditionalParameter(item.getKey(), item.getValue());
-				}
-			}
-			return boundSql;
-		}
 
 	}
+
 	// *****************************基本类型处理器*****************************
 
-	private static class ShortTypeHnadler implements VersionHandler<Short> {
+	private static class ShortTypeHandler implements VersionHandler<Short> {
+
 		public void plusVersion(Object paramObj, Field field, Short versionValue) throws Exception {
 			field.set(paramObj, (short) (versionValue + 1));
 		}
 	}
 
-	private static class IntegerTypeHnadler implements VersionHandler<Integer> {
+	private static class IntegerTypeHandler implements VersionHandler<Integer> {
+
 		public void plusVersion(Object paramObj, Field field, Integer versionValue) throws Exception {
 			field.set(paramObj, versionValue + 1);
 		}
 	}
 
-	private static class LongTypeHnadler implements VersionHandler<Long> {
+	private static class LongTypeHandler implements VersionHandler<Long> {
+
 		public void plusVersion(Object paramObj, Field field, Long versionValue) throws Exception {
 			field.set(paramObj, versionValue + 1);
 		}
@@ -316,12 +282,14 @@ public final class OptimisticLockerInterceptor implements Interceptor {
 
 	// ***************************** 时间类型处理器*****************************
 	private static class DateTypeHandler implements VersionHandler<Date> {
+
 		public void plusVersion(Object paramObj, Field field, Date versionValue) throws Exception {
 			field.set(paramObj, new Date());
 		}
 	}
 
 	private static class TimestampTypeHandler implements VersionHandler<Timestamp> {
+
 		public void plusVersion(Object paramObj, Field field, Timestamp versionValue) throws Exception {
 			field.set(paramObj, new Timestamp(new Date().getTime()));
 		}

+ 4 - 3
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/PerformanceInterceptor.java

@@ -30,7 +30,6 @@ import org.apache.ibatis.reflection.MetaObject;
 import org.apache.ibatis.reflection.SystemMetaObject;
 import org.apache.ibatis.session.ResultHandler;
 
-import com.alibaba.druid.pool.DruidPooledPreparedStatement;
 import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
 import com.baomidou.mybatisplus.toolkit.PluginUtils;
 import com.baomidou.mybatisplus.toolkit.SqlUtils;
@@ -65,9 +64,11 @@ public class PerformanceInterceptor implements Interceptor {
 		} else {
 			statement = (Statement) firstArg;
 		}
-		// TODO 这里不太对
-		if (statement instanceof DruidPooledPreparedStatement) {
+		try {
+			statement.getClass().getDeclaredField("stmt");
 			statement = (Statement) SystemMetaObject.forObject(statement).getValue("stmt.statement");
+		} catch (Exception e) {
+			// do nothing
 		}
 		String originalSql = statement.toString();
 		int index = originalSql.indexOf(':');

+ 146 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/H2UserTest.java

@@ -0,0 +1,146 @@
+package com.baomidou.mybatisplus.test.h2;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+import javax.sql.DataSource;
+
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.test.h2.entity.persistent.H2User;
+import com.baomidou.mybatisplus.test.h2.entity.service.IH2UserService;
+
+/**
+ * <p>
+ * Mybatis Plus H2 Junit Test
+ * </p>
+ *
+ * @author Caratacus
+ * @date 2017/4/1
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = { "classpath:h2/spring-test-h2.xml" })
+public class H2UserTest {
+
+    @BeforeClass
+    public static void initDB() throws SQLException,IOException {
+        @SuppressWarnings("resource")
+        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:h2/spring-test-h2.xml");
+        DataSource ds = (DataSource) context.getBean("dataSource");
+        try (Connection conn = ds.getConnection();) {
+            String createTableSql = readFile("user.ddl.sql");
+            Statement stmt = conn.createStatement();
+            stmt.execute(createTableSql);
+            stmt.execute("truncate table h2user");
+            insertUsers(stmt);
+            conn.commit();
+        }
+    }
+
+    private static void insertUsers(Statement stmt) throws SQLException, IOException{
+        String filename = "user.insert.sql";
+        String filePath = H2UserTest.class.getClassLoader().getResource("").getPath()+"/h2/"+filename;
+        try (
+                BufferedReader reader = new BufferedReader(new FileReader(filePath));
+        ) {
+            String line = null;
+            while ((line = reader.readLine()) != null){
+                stmt.execute(line.replace(";", ""));
+            }
+        }
+    }
+
+    private static String readFile(String filename) {
+        StringBuilder builder = new StringBuilder();
+        String filePath = H2UserTest.class.getClassLoader().getResource("").getPath()+"/h2/"+filename;
+        try (
+                BufferedReader reader = new BufferedReader(new FileReader(filePath));
+        ) {
+            String line = null;
+            while ((line = reader.readLine()) != null)
+                builder.append(line).append(" ");
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return builder.toString();
+    }
+
+    @Autowired
+    private IH2UserService userService;
+
+    @Test
+    public void testInsert(){
+        H2User user = new H2User();
+        user.setAge(1);
+        user.setPrice(new BigDecimal("9.99"));
+        userService.insert(user);
+        Assert.assertNotNull(user.getId());
+        user.setDesc("Caratacus");
+        userService.insertOrUpdate(user);
+        H2User userFromDB = userService.selectById(user.getId());
+        Assert.assertEquals("Caratacus", userFromDB.getDesc());
+    }
+
+    @Test
+    public void testUpdate(){
+
+    }
+
+    @Test
+    public void testDelete(){
+        H2User user = new H2User();
+        user.setAge(1);
+        user.setPrice(new BigDecimal("9.99"));
+        userService.insert(user);
+        Long userId = user.getId();
+        Assert.assertNotNull(userId);
+        userService.deleteById(userId);
+        Assert.assertNull(userService.selectById(userId));
+    }
+
+    @Test
+    public void testSelectByid(){
+        Long userId = 101L;
+        Assert.assertNotNull(userService.selectById(userId));
+    }
+
+    @Test
+    public void testSelectOne(){
+        H2User user = new H2User();
+        user.setId(105L);
+        EntityWrapper<H2User> ew = new EntityWrapper<>(user);
+        H2User userFromDB = userService.selectOne(ew);
+        Assert.assertNotNull(userFromDB);
+    }
+
+    @Test
+    public void testSelectList(){
+        H2User user = new H2User();
+        EntityWrapper<H2User> ew = new EntityWrapper<>(user);
+        List<H2User> list = userService.selectList(ew);
+        Assert.assertNotNull(list);
+        Assert.assertNotEquals(0,list.size());
+    }
+
+    @Test
+    public void testSelectPage(){
+        Page<H2User> page = userService.selectPage(new Page<H2User>(1,3));
+        Assert.assertEquals(3,page.getRecords().size());
+    }
+}

+ 41 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/config/DBConfig.java

@@ -0,0 +1,41 @@
+package com.baomidou.mybatisplus.test.h2.config;
+
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.h2.Driver;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.jdbc.datasource.SimpleDriverDataSource;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+/**
+ * <p>
+ * H2 Memory Database config
+ * </p>
+ *
+ * @author Caratacus
+ * @date 2017/4/1
+ */
+@Configuration
+@EnableTransactionManagement
+public class DBConfig {
+
+    @Bean
+    public DataSource dataSource() throws SQLException {
+        SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
+        dataSource.setDriver(new Driver());
+        dataSource.setUrl("jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
+        dataSource.setUsername("sa");
+        dataSource.setPassword("");
+        return dataSource;
+    }
+
+    @Bean
+    public DataSourceTransactionManager transactionManager(DataSource ds) {
+        return new DataSourceTransactionManager(ds);
+    }
+
+}

+ 54 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/config/MybatisPlusConfig.java

@@ -0,0 +1,54 @@
+package com.baomidou.mybatisplus.test.h2.config;
+
+import javax.sql.DataSource;
+
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.apache.ibatis.type.JdbcType;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.ResourceLoader;
+
+import com.baomidou.mybatisplus.MybatisConfiguration;
+import com.baomidou.mybatisplus.MybatisXMLLanguageDriver;
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
+import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
+
+/**
+ * <p>
+ * TODO class
+ * </p>
+ *
+ * @author Caratacus
+ * @date 2017/4/1
+ */
+@Configuration
+@MapperScan("com.baomidou.mybatisplus.test.h2.entity.mapper")
+public class MybatisPlusConfig {
+
+    @Bean("mybatisSqlSession")
+    public SqlSessionFactory sqlSessionFactory (DataSource dataSource, ResourceLoader resourceLoader, GlobalConfiguration globalConfiguration) throws Exception {
+        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
+        sqlSessionFactory.setDataSource(dataSource);
+//        sqlSessionFactory.setConfigLocation(resourceLoader.getResource("classpath:mybatis-config.xml"));
+        sqlSessionFactory.setTypeAliasesPackage("com.baomidou.mybatisplus.test.h2.entity.persistent");
+        MybatisConfiguration configuration = new MybatisConfiguration();
+        configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
+        configuration.setJdbcTypeForNull(JdbcType.NULL);
+        sqlSessionFactory.setConfiguration(configuration);
+        PaginationInterceptor pagination = new PaginationInterceptor();
+        pagination.setDialectType("h2");
+        sqlSessionFactory.setPlugins(new Interceptor[]{
+            pagination
+        });
+        sqlSessionFactory.setGlobalConfig(globalConfiguration);
+        return sqlSessionFactory.getObject();
+    }
+
+    @Bean
+    public GlobalConfiguration globalConfiguration(){
+        return new GlobalConfiguration();
+    }
+}

+ 16 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/mapper/H2UserMapper.java

@@ -0,0 +1,16 @@
+package com.baomidou.mybatisplus.test.h2.entity.mapper;
+
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.baomidou.mybatisplus.test.h2.entity.persistent.H2User;
+
+/**
+ * <p>
+ * TODO class
+ * </p>
+ *
+ * @author Caratacus
+ * @date 2017/4/1
+ */
+public interface H2UserMapper extends BaseMapper<H2User> {
+
+}

+ 172 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/persistent/H2User.java

@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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 com.baomidou.mybatisplus.test.h2.entity.persistent;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import com.baomidou.mybatisplus.annotations.TableField;
+import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.annotations.TableName;
+import com.baomidou.mybatisplus.annotations.Version;
+import com.baomidou.mybatisplus.enums.FieldStrategy;
+
+/**
+ * <p>
+ * 测试用户类
+ * </p>
+ *
+ * @author hubin sjy
+ */
+/* 表名 value 注解【 驼峰命名可无 】, resultMap 注解测试【 映射 xml 的 resultMap 内容 】 */
+@TableName
+public class H2User implements Serializable {
+
+	/* 表字段注解,false 表中不存在的字段,可无该注解 默认 true */
+	@TableField(exist = false)
+	private static final long serialVersionUID = 1L;
+
+	/* 主键ID 注解,value 字段名,type 用户输入ID */
+	@TableId(value = "test_id")
+	private Long id;
+
+	/* 测试忽略验证 */
+	private String name;
+
+	private Integer age;
+	
+	/*BigDecimal 测试*/
+	private BigDecimal price;
+
+	/* 测试下划线字段命名类型, 字段填充 */
+	@TableField(value = "test_type", validate = FieldStrategy.IGNORED)
+	private Integer testType;
+
+	private String desc;
+	
+	@Version
+	private Integer version;
+
+
+	public H2User() {
+
+	}
+
+	public H2User(String name) {
+		this.name = name;
+	}
+
+	public H2User(Integer testType) {
+		this.testType = testType;
+	}
+
+	public H2User(String name, Integer age) {
+		this.name = name;
+		this.age = age;
+	}
+
+	public H2User(Long id, String name) {
+		this.id = id;
+		this.name = name;
+	}
+
+	public H2User(Long id, Integer age) {
+		this.id = id;
+		this.age = age;
+	}
+
+	public H2User(Long id, String name, Integer age, Integer testType) {
+		this.id = id;
+		this.name = name;
+		this.age = age;
+		this.testType = testType;
+	}
+
+	public H2User(String name, Integer age, Integer testType) {
+		this.name = name;
+		this.age = age;
+		this.testType = testType;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public BigDecimal getPrice() {
+		return price;
+	}
+
+	public void setPrice(BigDecimal price) {
+		this.price = price;
+	}
+
+	public Integer getAge() {
+		return age;
+	}
+
+	public void setAge(Integer age) {
+		this.age = age;
+	}
+
+	public Integer getTestType() {
+		return testType;
+	}
+
+	public void setTestType(Integer testType) {
+		this.testType = testType;
+	}
+
+	public String getDesc() {
+		return desc;
+	}
+
+	public void setDesc(String desc) {
+		this.desc = desc;
+	}
+
+	public Integer getVersion() {
+		return version;
+	}
+
+	public void setVersion(Integer version) {
+		this.version = version;
+	}
+
+	@Override
+	public String toString() {
+		return "H2User{" +
+				"id=" + id +
+				", name='" + name + '\'' +
+				", age=" + age +
+				", price=" + price +
+				", testType=" + testType +
+				", desc='" + desc + '\'' +
+				", version=" + version +
+				'}';
+	}
+}

+ 31 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/service/IH2UserService.java

@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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 com.baomidou.mybatisplus.test.h2.entity.service;
+
+import com.baomidou.mybatisplus.service.IService;
+import com.baomidou.mybatisplus.test.h2.entity.persistent.H2User;
+
+/**
+ * <p>
+ * Service层测试
+ * </p>
+ * 
+ * @author hubin
+ * @date 2017-01-30
+ */
+public interface IH2UserService extends IService<H2User> {
+
+}

+ 36 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/h2/entity/service/impl/H2UserServiceImpl.java

@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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 com.baomidou.mybatisplus.test.h2.entity.service.impl;
+
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.service.impl.ServiceImpl;
+import com.baomidou.mybatisplus.test.h2.entity.mapper.H2UserMapper;
+import com.baomidou.mybatisplus.test.h2.entity.persistent.H2User;
+import com.baomidou.mybatisplus.test.h2.entity.service.IH2UserService;
+
+/**
+ * <p>
+ * Service层测试
+ * </p>
+ * 
+ * @author hubin
+ * @date 2017-01-30
+ */
+@Service
+public class H2UserServiceImpl extends ServiceImpl<H2UserMapper, H2User> implements IH2UserService {
+
+}

+ 2 - 2
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/plugins/optimisticLocker/CreateDB.sql

@@ -10,8 +10,8 @@ CREATE TABLE version_user (
 ) ENGINE = INNODB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8;
 
 insert into version_user (id,name,version) values(1,"zhangsan",15);
-insert into version_user (id,name,version) values(2,"wangwu",109);
-insert into version_user (id,name,version) values(3,"lisi",null);
+insert into version_user (id,name,version) values(2,"lisi",109);
+insert into version_user (id,name,version) values(3,"wangwu",null);
 
 DROP TABLE
 IF EXISTS time_version_user;

+ 63 - 19
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/plugins/optimisticLocker/OptimisticLockerInterceptorTest.java

@@ -4,6 +4,7 @@ import java.io.Reader;
 import java.sql.Connection;
 import java.sql.Timestamp;
 import java.util.Date;
+import java.util.Random;
 
 import org.apache.ibatis.io.Resources;
 import org.apache.ibatis.jdbc.ScriptRunner;
@@ -34,6 +35,7 @@ import com.baomidou.mybatisplus.test.plugins.optimisticLocker.mapper.TimestampVe
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration(locations = { "/plugins/optimisticLockerInterceptor.xml" })
 public class OptimisticLockerInterceptorTest {
+
 	@Autowired
 	private ShortVersionUserMapper shortVersionUserMapper;
 	@Autowired
@@ -62,14 +64,14 @@ public class OptimisticLockerInterceptorTest {
 	}
 
 	@Test
-	public void shorttVersionTest() {
+	public void shortVersionTest() {
 		// 查询数据
 		ShortVersionUser versionUser = shortVersionUserMapper.selectById(1);
 		Short originVersion = versionUser.getVersion();
 		// 更新数据
 		versionUser.setName("苗神");
 		shortVersionUserMapper.updateById(versionUser);
-		Assert.assertTrue(versionUser.getVersion() == originVersion + 1);
+		Assert.assertTrue(shortVersionUserMapper.selectById(1).getVersion() == originVersion + 1);
 	}
 
 	@Test
@@ -80,7 +82,7 @@ public class OptimisticLockerInterceptorTest {
 		// 更新数据
 		versionUser.setName("苗神");
 		intVersionUserMapper.updateById(versionUser);
-		Assert.assertTrue(versionUser.getVersion() == originVersion + 1);
+		Assert.assertTrue(intVersionUserMapper.selectById(1).getVersion() == originVersion + 1);
 
 		// 重复测试一次,验证动态参数覆盖
 		// 查询数据
@@ -90,14 +92,14 @@ public class OptimisticLockerInterceptorTest {
 		// 更新数据
 		versionUser2.setName("苗神");
 		intVersionUserMapper.updateById(versionUser2);
-		Assert.assertTrue(versionUser2.getVersion() == originVersion2 + 1);
+		Assert.assertTrue(intVersionUserMapper.selectById(2).getVersion() == originVersion2 + 1);
 
 		// 测试一次数据库中version为null
 		IntVersionUser versionUser3 = intVersionUserMapper.selectById(3);
 		// 更新数据
 		versionUser3.setName("苗神");
 		intVersionUserMapper.updateById(versionUser3);
-		Assert.assertTrue(versionUser3.getVersion() == null);
+		Assert.assertTrue(intVersionUserMapper.selectById(3).getVersion() == null);
 
 	}
 
@@ -109,7 +111,7 @@ public class OptimisticLockerInterceptorTest {
 		// 更新数据
 		versionUser.setName("苗神");
 		longVersionUserMapper.updateById(versionUser);
-		Assert.assertTrue(versionUser.getVersion() == originVersion + 1);
+		Assert.assertTrue(longVersionUserMapper.selectById(1).getVersion() == originVersion + 1);
 	}
 
 	@Test
@@ -122,9 +124,10 @@ public class OptimisticLockerInterceptorTest {
 		versionUser.setVersion(originVersion);
 		dateVersionUserMapper.insert(versionUser);
 		// 更新数据
-		versionUser.setName("小锅盖");
-		dateVersionUserMapper.updateById(versionUser);
-		Assert.assertTrue(versionUser.getVersion().after(originVersion));
+		DateVersionUser q = dateVersionUserMapper.selectById(15);
+		q.setName("小锅盖");
+		dateVersionUserMapper.updateById(q);
+		Assert.assertTrue(dateVersionUserMapper.selectById(15L).getVersion().after(originVersion));
 	}
 
 	@Test
@@ -137,20 +140,48 @@ public class OptimisticLockerInterceptorTest {
 		versionUser.setVersion(originVersion);
 		timestampVersionUserMapper.insert(versionUser);
 		// 更新数据
-		versionUser.setName("小锅盖");
-		timestampVersionUserMapper.updateById(versionUser);
-		Assert.assertTrue(versionUser.getVersion().after(originVersion));
+		TimestampVersionUser q = timestampVersionUserMapper.selectById(15);
+		q.setName("小锅盖");
+		timestampVersionUserMapper.updateById(q);
+		Assert.assertTrue(timestampVersionUserMapper.selectById(15L).getVersion().after(originVersion));
 	}
 
 	@Test
 	public void stringVersionTest() {
 		// 查询数据
 		StringVersionUser versionUser = stringersionUserMapper.selectById(1);
-		String originVersion = versionUser.getVersion();
+		String originVersion = versionUser.getTt();
 		// 更新数据
 		versionUser.setName("苗神");
 		stringersionUserMapper.updateById(versionUser);
-		Assert.assertEquals(versionUser.getVersion(), String.valueOf(Long.parseLong(originVersion) + 1));
+		Assert.assertEquals(stringersionUserMapper.selectById(1).getTt(), String.valueOf(Long.parseLong(originVersion) + 1));
+	}
+
+	@Test
+	public void multiThreadVersionTest() {
+		final Random random = new Random();
+		for (int i = 50; i < 150; i++) {
+			new Thread(new Runnable() {
+				public void run() {
+					IntVersionUser intVersionUser = new IntVersionUser();
+					long id = random.nextLong();
+					intVersionUser.setId(id);
+					int version = random.nextInt();
+					intVersionUser.setName("改前" + version);
+					intVersionUser.setVersion(version);
+					intVersionUserMapper.insert(intVersionUser);
+					intVersionUser.setName("改后" + version);
+					intVersionUserMapper.updateById(intVersionUser);
+					Assert.assertTrue(intVersionUserMapper.selectById(id).getVersion() == version + 1);
+				}
+			}, "编号" + i).start();
+		}
+
+		try {
+			Thread.sleep(4000);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		}
 	}
 
 	@Test
@@ -158,10 +189,23 @@ public class OptimisticLockerInterceptorTest {
 		// 查询数据
 		IntVersionUser versionUser = intVersionUserMapper.selectById(2);
 		Integer originVersion = versionUser.getVersion();
-		// 更新数据
-		IntVersionUser intVersionUser = new IntVersionUser();
-		intVersionUser.setName("苗神");
-		intVersionUserMapper.update(versionUser, new EntityWrapper<IntVersionUser>(versionUser));
-		Assert.assertTrue(versionUser.getVersion() == originVersion + 1);
+		// null条件
+		intVersionUserMapper.update(versionUser, null);
+		Assert.assertTrue(intVersionUserMapper.selectById(2).getVersion() == originVersion);
+		// 空条件
+		intVersionUserMapper.update(versionUser, new EntityWrapper<IntVersionUser>());
+		Assert.assertTrue(intVersionUserMapper.selectById(2).getVersion() == originVersion);
+		// 正常查询不带version
+		IntVersionUser wrapper = new IntVersionUser();
+		wrapper.setName("lisi");
+		intVersionUserMapper.update(versionUser, new EntityWrapper<IntVersionUser>(wrapper));
+		Assert.assertTrue(intVersionUserMapper.selectById(2).getVersion() == originVersion + 1);
+		// 原始条件带version按原始逻辑走
+		IntVersionUser wrapper2 = new IntVersionUser();
+		wrapper2.setName("lisi");
+		wrapper2.setVersion(originVersion + 1);
+		intVersionUserMapper.update(versionUser, new EntityWrapper<IntVersionUser>(wrapper2));
+		Assert.assertTrue(intVersionUserMapper.selectById(1).getVersion() == originVersion + 1);
+
 	}
 }

+ 6 - 5
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/plugins/optimisticLocker/entity/StringVersionUser.java

@@ -17,7 +17,8 @@ public class StringVersionUser implements Serializable {
 	private String name;
 
 	@Version
-	private String version;
+	@TableField("version")
+	private String tt;
 
 	public Long getId() {
 		return id;
@@ -35,12 +36,12 @@ public class StringVersionUser implements Serializable {
 		this.name = name;
 	}
 
-	public String getVersion() {
-		return version;
+	public String getTt() {
+		return tt;
 	}
 
-	public void setVersion(String version) {
-		this.version = version;
+	public void setTt(String tt) {
+		this.tt = tt;
 	}
 
 }

+ 12 - 0
mybatis-plus/src/test/resources/h2/spring-test-h2.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
+	xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:mvc="http://www.springframework.org/schema/mvc"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
+           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd  
+           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
+
+	<context:component-scan base-package="com.baomidou.mybatisplus.test.h2" />
+
+</beans>

+ 12 - 0
mybatis-plus/src/test/resources/h2/user.ddl.sql

@@ -0,0 +1,12 @@
+CREATE TABLE IF NOT EXISTS  h2user (
+	test_id BIGINT(20) NOT NULL ,
+	name VARCHAR(30) NULL DEFAULT NULL ,
+	age INT(11) NULL DEFAULT NULL ,
+	test_type INT(11) NULL ,
+	test_date DATETIME NULL DEFAULT NULL,
+	price DECIMAL(10,2) NULL DEFAULT NULL,
+	desc VARCHAR(30) NULL DEFAULT NULL ,
+	version INT(5) NULL DEFAULT NULL,
+	PRIMARY KEY (test_id)
+)
+

+ 5 - 0
mybatis-plus/src/test/resources/h2/user.insert.sql

@@ -0,0 +1,5 @@
+insert into h2user(test_id, name, test_date, age, price, test_type, version) values (101,'Tomcat', '2017-1-1 1:1:1', 3, 9.99, 1, 1),
+insert into h2user(test_id, name, test_date, age, price, test_type, version) values (102,'Jerry', '2017-3-1 1:1:1', 2, 19.99, 1, 1);
+insert into h2user(test_id, name, test_date, age, price, test_type, version) values (103,'Bob', '2017-4-1 1:1:1', 13, 99.99, 1, 1);
+insert into h2user(test_id, name, test_date, age, price, test_type, version) values (104,'Joe', '2017-2-1 1:1:1', 18, 1.99, 1, 1);
+insert into h2user(test_id, name, test_date, age, price, test_type, version) values (105,'Tony', '2017-2-1 1:1:1', 18, 1.99, 1, 1);

+ 2 - 1
mybatis-plus/src/test/resources/plugins/optimisticLockerInterceptor.xml

@@ -19,7 +19,7 @@
 			value="com.baomidou.mybatisplus.test.plugins.optimisticLocker.entity" />
 		<property name="plugins">
 			<array>
-				<bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor" />
+				
 				<bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor">
 					<property name="properties">
 						<value>
@@ -27,6 +27,7 @@
 						</value>
 					</property>
 				</bean>
+				<bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor" />
 			</array>
 		</property>
 	</bean>