业务背景
由于新业务需要,数据库名称要更换,代码中存在许多数据库名.表明的SQL语句,如:db.user,更换db名称后原代码执行报错,需将SQL语句db名字换为新的数据库名称.
使用Mybatis拦截器实现动态修改sql语句
@Component
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class, Integer.class })})
public class MybatisInterceptor implements Interceptor {
//注入配置文件中定义的全局数据库名称
@Autowired
ScmGobalDbDefinition scmGobalDbDefinition;
@Override
public Object intercept(Invocation invocation) throws Throwable {
RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget();
String sql = handler.getBoundSql().getSql().toLowerCase();
Map<String, String> scmDbs = scmGobalDbDefinition.getScmDbs();
Set<String> dbs = scmDbs.keySet();
for(String db:dbs){
if(sql.toLowerCase().contains(db)){
sql=sql.replaceAll(db,scmDbs.get(db));
}
//将修改后的sql 更新至BoundSql对象中
BoundSql boundSql = handler.getBoundSql();
Field field = boundSql.getClass().getDeclaredField("sql");
field.setAccessible(true);
field.set(boundSql, sql);
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
配置文件中注入Map对象
@Component
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "scmGobalDb")
public class ScmGobalDbDefinition {
private Map<String,String> scmDbs;
public Map<String, String> getScmDbs() {
return scmDbs;
}
public void setScmDbs(Map<String, String> scmDbs) {
this.scmDbs = scmDbs;
}
}
application.yml 配置
scmGobalDb:
scmDbs:
db1: ry_db1
db2: ry_db2
db3: ry_db3