一、背景
根据信创国产适配要求,针对业务系统迁移至达梦数据库,保持系统稳定、可靠。
当前系统技术栈:springboot+mybatis(3.5.9)+mybaits plus
我们采用的是拦截器方案,结合JavaAgent字节码增强技术,实现最小化代码改动。
二、迁移方案
- 通过拦截器实现
- 通过mybatis自带的databaseId 多数据源机制
三、梳理现有使用方式
使用方式 | demoMapperXml | demoMapperAnno | demoMapper | demoBeanService | queryWrap |
---|
四、方案实现
3.1 拦截器方式实现
主要实现两个拦截器:
拦截器 | 作用 | 备注 |
---|---|---|
mapper调用方法级别拦截器 | 拦截复杂sql的执行方法 | 精确到单个方法的拦截,仅对达梦不支持的方法进行更改 |
sql函数拦截器 | 简单的函数替换例如(group_concat->WM_CONCA ) |
3.1.1 方法拦截器
实现原理:
- 在MyBatis调用Mapper方法时进行拦截
- 自动将原方法调用重定向到对应的DM版本方法
示例:
// 原方法
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(@Param("id") Long id);
// DM专用方法(仅当原SQL不兼容时需实现)
@Select("SELECT * FROM user WHERE id = #{id}") // 修改后的DM兼容SQL
User selectByIdDM(@Param("id") Long id);
拦截逻辑:
- 检查是否存在
原方法名+DM
后缀的方法 - 存在则调用DM版本方法,否则调用原方法
3.1.2 sql函数拦截器
对sql的进行拦截并处理,处理简单函数转换
例如:
group_concat
→WM_CONCAT
迁移SQL分类处理
类别 | 处理方式 | 示例 |
---|---|---|
无需更改 | 直接执行 | dm可以执行的sql |
仅替换函数 | 函数拦截器处理 | GROUP_CONCAT→WM_CONCAT |
需要重写SQL | 方法拦截器+DM方法 | replace to > merge into |
重写SQL+替换函数 | 方法拦截器+DM方法 | 包含特殊函数的复杂查询 |
代码整体情况
方法拦截器代码
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
@Log
public class DmMethodRouterInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// System.out.println("DmMethodRouterInterceptor.intercept()");
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
String methodId = ms.getId();
// 如果是DM数据库且方法名不带Dm后缀
if ( !methodId.endsWith("DM")) {
try {
// 尝试查找对应的Dm方法
Configuration configuration =