仅供参考,不做投资建议。仅说明一个实现原理,线上使用需要进行更可靠的验证。

本地测试的时候有时候会有多库进行的测试,这个时候又不想污染数据,又不想每次都删除,苦于目前没有好的多数据源事务,撸了一个。

大家不要急着喷我,开发测试不总是那么规范的.

只讨论单个项目多数据源的情况,不同项目不同的数据源涉及到了分布式事务,超出本人能力范围.

单数据源

单数据源时代,一切都很美好,天还是蓝的,水还是绿的。 事务还是可以正常使用的.

使用实例

  1. @Configuration
  2. @EnableTransactionManagement(proxyTargetClass = true)
  3. @ConfigurationProperties(prefix = "raycloud.datasource")
  4. @Data
  5. public class DatasourceAutoConfigure implements InitializingBean {
  6. ....
  7. }

然而这个美好的故事并没有持续多长时间,随着年纪的长大,自我意识的膨胀,一个库已经满足不了我们日益增长的需求了. 迎来了多数据源的时候.

多数据源

单数据源事务的本质是采用了AOP切面的方式执行了事务的一系列方法,来避免人为手工的控制这些数据.

  1. set autocommit = 0
  2. update table_name set xx = '-1' where id = 2;
  3. commit
  4. set autocommit = 1

而在多数据源中,因为 Spring 仅仅只是对单个数据源进行了控制了,所以当前情况下必然存在多数据源事务的问题.

而多数据源它本身其实是一个特殊的单一数据源,这么来理解,随后进行编码就会容易需要,因为只有一个数据源的情况下,spring是可以进行控制的,而这个单一的多数据源包含了多个数据源,这么说可能有点绕,用代码翻译一下

  1. # 数据源1
  2. set autocommit = 0
  3. # 数据源2
  4. set autocommit = 0
  5. # 数据源1
  6. update table_name set xx = '-1' where id = 2;
  7. # 数据源2
  8. update table_name_2 set xx = '-1' where id = 2;
  9. # 数据源1
  10. commit
  11. set autocommit = 1
  12. # 数据源2
  13. commit
  14. set autocommit = 1

所以我们需要自定义一个DataSourceTransactionManager来对所有注册的DatasourceTrsactionManager来进行控制,必然达到一荣俱荣,一损俱损的效果即可.

为了充分的理解 Spring 是如何操作单个数据源的,必须先明白Spring是如何将事务串联起来的,ThreadLocal, 为什么在目前的Spring版本中不能异步提交事务,就是这个原因,他的begin,commit/rollback 都是和这个ThreadLocal上下文的Datasource(更具体的Connection)来进行绑定的。
image.png
这就是明证,既然已经明白了他的本质,那么改造就成了可操作的,可落地的一件事。代码截图如下
image.png
上述代码,大部分来源于Spring本身,我们不生产代码,只是代码的搬运工

image.png
改变的核心代码。 本来ThreadLocal是和单个Connection绑定,稍作修改,我让他和整个Datasource绑定。事情就成了。
image.png

说,大家都会,然后我抓包明证。 multi-datasource.pcapng.zip
将该文件使用用wireshark打开即可,证明