@DS(“XXX”) + @Transactional > table not exist?
今年年初项目引入了 dynamic-datasource ,用于满足业务联动下的多个数据源之间的CRUD。然而在使用的过程中发现,只要在方法上 或者类上 存在这个组合@DS(“XXX”) + @Transactional, 业务流程就会卡住并抛出 XXX table not exist的异常, 移除@Transactional 之后,业务正常进行。 但是这样带来了巨大的隐患,即:出现异常无法回滚。 然鹅,因为项目周期短,节奏快,时间紧,一直没有时间去处理这块的东西。 这个问题的关键在于事务
spring 的事务背后是啥?怎么弄?
这里不赘述事务的定义, 从流程上,非常表面的来看,开启一个spring 的事务就是一个从既定数据源获取不设置自动提交的数据库链接。 流程复盘一下,重点在前4步:
- 从DataSource 中获取链接(connection)
- 不设置自动提交 ;
- 缓存该链接;
- 执行业务SQL,但是会从当前线程中获取缓存下来的链接
- 判断是否设置了自动提交;
- 执行对应的sql;
- …
这意味着,当某个业务逻辑中,需要操作其他数据源会有问题,比如
@Transactional
public void a() {
this.b();
}
@DS("b-source")
public void b() {
// 数据库操作 CRUD
}
因为当前事务背后的数据库链接并非b-source,这种写法也并不能正常切换到b-source 数据源中。所以我们需要手动指定Spring事务传播属性 propagation; 结合事务的流程,上面的代码我们改成这样:
@Transactional
public void a() {
// a-source 数据源中的各种逻辑操作
this.b();
}
@DS("b-source")
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void b() {
// 数据库操作 CRUD
}
回滚属性可以自己定义,这里不再补充。 现在上面这段代码的意思就是执行到b时,重新创建一个事务,完成数据源切换。执行b-source 数据源中的所有crud 操作。虽然它能正常工作了,但是这样也增加了代码的复杂度。
有没有其他方式?
当然有,目前我们项目使用了 Sharding-JDBC 完善对多数据源的支持。
传送门 : Sharding-JDBC官网 一份配置好的文件, 就可以避开以上遇到的问题,框架切换基本能做到无感切换。 但是作为一个新框架,shardingJDBC 在SQL 语法的支持上,有一些欠缺,具体可以去看官网。 这里重点提一下 关键字的问题,如果我们数据库建表时某些字段与shardingJDBC 的关键字有冲突(比如某字段名叫 ‘json’),则无法正常执行SQL。 关于shardingJDBC 的后续。用了一段时间之后再记录