MyBatis - 自动区分环境
2018-11-11 本文已影响13人
齐晋
更多MyBatis实战内容,请参考:MyBatis - 实战指南
背景
在开发时,经常会用到测试,甚至是压测。测试数据应该是与正式数据区分开来的。怎么区分呢?我们可以在数据库中的每个表中都添加一个env
字段,来表示环境。当env
字段为0
时,表示为测试数据,为1
时表示为正式数据。
在实际使用时,怎么给env设置值呢?
我们可以根据域名来进行区分。比如当域名为api.xxx.com
时,表示是正式环境的数据,env
设置为1
;而当域名是api.test.xxx.com
时,表示为测试环境数据,env
设置为0
实现方法
在数据库中,env
字段是TINYINT
,对于的JavaType是EnvEnum
:
public enum EnvEnum{
Product(1,"生产环境"),VIRTUAL(0,"虚拟环境");
}
这里,我们假设env字段已经根据域名被设置到ThreadLocal中了。那么在实现拦截器的时候,直接从ThreadLocal中取就是了:
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class EnvInterceptor implements Interceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(EnvInterceptor.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
Object object = invocation.getArgs()[1];
//sql类型
SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
if (SqlCommandType.INSERT.equals(sqlCommandType)) {
//插入操作时,自动插入env。TraceUtil从ThreadLocal众获取env的值
EnvEnum envEnum = TraceUtil.getEnv();
Field fieldEnv = object.getClass().getDeclaredField("env");
fieldEnv.setAccessible(true);
fieldEnv.set(object, envEnum);
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
最后,注册拦截器到MyBatis plugin:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<plugins>
<plugin interceptor="com.aviagames.commons.mybatis.interceptor.EnvInterceptor"></plugin>
</plugins>
</configuration>