仅供参考,不做投资建议。仅说明一个实现原理,线上使用需要进行更可靠的验证。
本地测试的时候有时候会有多库进行的测试,这个时候又不想污染数据,又不想每次都删除,苦于目前没有好的多数据源事务,撸了一个。
大家不要急着喷我,开发测试不总是那么规范的.
只讨论单个项目多数据源的情况,不同项目不同的数据源涉及到了分布式事务,超出本人能力范围.
单数据源
单数据源时代,一切都很美好,天还是蓝的,水还是绿的。 事务还是可以正常使用的.
使用实例
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@ConfigurationProperties(prefix = "raycloud.datasource")
@Data
public class DatasourceAutoConfigure implements InitializingBean {
....
}
然而这个美好的故事并没有持续多长时间,随着年纪的长大,自我意识的膨胀,一个库已经满足不了我们日益增长的需求了. 迎来了多数据源的时候.
多数据源
单数据源事务的本质是采用了AOP切面的方式执行了事务的一系列方法,来避免人为手工的控制这些数据.
set autocommit = 0
update table_name set xx = '-1' where id = 2;
commit
set autocommit = 1
而在多数据源中,因为 Spring
仅仅只是对单个数据源进行了控制了,所以当前情况下必然存在多数据源事务的问题.
而多数据源它本身其实是一个特殊的单一数据源,这么来理解,随后进行编码就会容易需要,因为只有一个数据源的情况下,spring是可以进行控制的,而这个单一的多数据源包含了多个数据源,这么说可能有点绕,用代码翻译一下
# 数据源1
set autocommit = 0
# 数据源2
set autocommit = 0
# 数据源1
update table_name set xx = '-1' where id = 2;
# 数据源2
update table_name_2 set xx = '-1' where id = 2;
# 数据源1
commit
set autocommit = 1
# 数据源2
commit
set autocommit = 1
所以我们需要自定义一个DataSourceTransactionManager来对所有注册的DatasourceTrsactionManager来进行控制,必然达到一荣俱荣,一损俱损的效果即可.
为了充分的理解 Spring
是如何操作单个数据源的,必须先明白Spring是如何将事务串联起来的,ThreadLocal, 为什么在目前的Spring版本中不能异步提交事务,就是这个原因,他的begin,commit/rollback 都是和这个ThreadLocal上下文的Datasource(更具体的Connection)来进行绑定的。
这就是明证,既然已经明白了他的本质,那么改造就成了可操作的,可落地的一件事。代码截图如下
上述代码,大部分来源于Spring本身,我们不生产代码,只是代码的搬运工。
改变的核心代码。 本来ThreadLocal是和单个Connection绑定,稍作修改,我让他和整个Datasource绑定。事情就成了。
说,大家都会,然后我抓包明证。 multi-datasource.pcapng.zip
将该文件使用用wireshark打开即可,证明