记录开发环境中Spring声明式事务+Sharding-JDBC读写分离的一次踩坑
问题现象:
在一个Spring声明式事务方法中有两个SQL操作,先插入一条新数据,再删除特定数据。这个方法有时候会出现删除操作等待锁超时问题。
问题定位:
-
在MySQL客户端测试这个事务,问题不能重现。
-
查看锁超时时候,MySQL的事务,锁的情况。发现有两个事务,删除操作会等待锁超时。 查看MYSQL的事务,锁,锁等待。
select * from information_schema.INNODB_TRX;
select * from information_schema.INNODB_LOCKS;
select * from information_schema.INNODB_LOCK_WAITS;
-
代码中声明了一个事务,为什么数据库中会有两个事务呢?怀疑跟Sharding-JDBC配置有关系,在开发环境中主从库是同一个数据库。
-
开启Sharding-JDBC的日志,日志会记录SQL是由哪个数据源执行的。
Spring.shardingsphere.props.sql.show = true
-
开启日志后发现问题,发现插入SQL的执行数据源是master, 删除SQL数据源是slave. 这就是为什么有两个事务的原因,因为是两个数据库连接。
问题解决:
定位问题后,发现是sharding-jdbc的masterslave配置有问题,配置了masterslave之后,路由规则才正确的成了mastersalve, 这样这个事务就会是同一个数据源连接,保证了真正的事务提交。
spring:
shardingsphere:
masterslave:
load-balance-algorithm-type: xxx
name: xx
master-data-source-name: xxx
slave-data-source-names: xxx
总结:
参考sharding-jdbc的处理事物的方式。一个ShardingConnection会执行多条SQL,可能会涉及不同的数据源,如果SQL执行不会出现逻辑异常的话,会最后统一进行提交。
如果不同的数据源连接的是同一个数据库,并且SQL之间有锁等待的话,可能会出现锁等待超时,因为在最后阶段才会进行事务提交。