最近用tkmybatis插件做项目时,发现在事务中有些新插入的数据需要被用到主键,主键不能回写,特意查了下原先作者的文档和博客,发现没有uuid的回写实现,只能自己写个用下,现发出来分享下,愿以后的小伙伴都能有分享精神。
主键采用UUID时主键回写的两种解决方案,都是才用mybatis插件形式实现。
@Intercepts({
@Signature(type=StatementHandler.class, method="update", args={ Statement.class }),
@Signature(type=Executor.class, method="update", args={MappedStatement.class, Object.class})
})
public class BackWriteInterceptor implements Interceptor {
private static final String DEFAULT_PRIMARY_KEY_NAME = "uid";
private static final ThreadLocal<Boolean> LOCAL_BACK_WRITE = new ThreadLocal<Boolean>();
private String primaryKeyPropertyName = DEFAULT_PRIMARY_KEY_NAME;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object target = invocation.getTarget();
if (target instanceof StatementHandler) {
return doInterceptStatementHandler(invocation, (StatementHandler) target);
} else if (target instanceof Executor) {
Object[] args = invocation.getArgs();
return doInterceptExecutor(invocation, (MappedStatement) args[0], args[1]);
}
return invocation.proceed();
}
private Object doInterceptExecutor(Invocation invocation, MappedStatement ms, Object argument)
throws Throwable {
if (ms.getSqlCommandType().equals(SqlCommandType.INSERT)
&& argument instanceof PO) {
LOCAL_BACK_WRITE.set(true);
}
try {
return invocation.proceed();
} catch (Exception e) {
throw e;
} finally {
LOCAL_BACK_WRITE.remove();
}
}
private Object doInterceptStatementHandler(Invocation invocation, StatementHandler statementHandler)
throws Throwable {
Boolean localBackWrite = LOCAL_BACK_WRITE.get();
BoundSql boundSql = statementHandler.getBoundSql();
Object parameterObject = boundSql.getParameterObject();
if (localBackWrite != null && localBackWrite && parameterObject instanceof PO) {
String uid = (String) boundSql.getAdditionalParameter(this.primaryKeyPropertyName + "_bind");
((PO) parameterObject).setUid(uid);
LOCAL_BACK_WRITE.set(false);
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler || target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties properties) {
if (properties.containsKey("primaryKeyPropertyName")) {
primaryKeyPropertyName = (String) properties.get("primaryKeyPropertyName");
}
}
}
2)自定义KeyGenerator
@Intercepts(@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}))
public class BackWriteInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object argument = args[1];
if(ms.getSqlCommandType().equals(SqlCommandType.INSERT) &&
NoKeyGenerator.class.equals(ms.getKeyGenerator().getClass()) &&
PO.class.isAssignableFrom(argument.getClass())) {
MetaObject metaObject = SystemMetaObject.forObject(ms);
metaObject.setValue("keyGenerator", BackWriteKeyGenerator.instance());
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties properties) {
}
}
public class BackWriteKeyGenerator implements KeyGenerator {
private static final BackWriteKeyGenerator instance = new BackWriteKeyGenerator();
public static BackWriteKeyGenerator instance() {
return instance;
}
@Override
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
if (parameter instanceof PO) {
((PO) parameter).setUid(UUID.randomUUID().toString().replaceAll("-", ""));
}
}
@Override
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
}
}
两种方案各有优劣,有兴趣的可以自己研究下。