Closed yougecn closed 4 months ago
发现存在问题的seata版本有2.0.0和1.8.0 同一个全局事务中,不同的分支事务操作同一条记录,锁重入后,lockDOs因lock_table.row_key中表名大小写问题去重失败,导致分支事务报LockWaitTimeoutException: Global lock wait timeout,LockConflictException: get global lock fail, xid,server端报Global lock acquire failed; 原因是:AbstractLocker中protected String getRowKey(String resourceId, String tableName, String pk) { return new StringBuilder().append(resourceId).append(LOCK_SPLIT).append(tableName).append(LOCK_SPLIT).append(pk) .toString(); }的表名应该是来自与sql语句,sql语句中的表名大小写决定了rowKey中表名的大小写;导致如果同一个全局事务中不同分支事务间修改同一条记录时表名有的大写有的小写,导致 LockStoreDataBaseDAO中 // If the lock has been exists in db, remove it from the lockDOs if (CollectionUtils.isNotEmpty(dbExistedRowKeys)) { unrepeatedLockDOs = lockDOs.stream().filter(lockDO -> !dbExistedRowKeys.contains(lockDO.getRowKey())) .collect(Collectors.toList()); } 这里去重失败 建议row_key中的表名统一转为大写;比如在AbstractLocker.getRowKey中将表名转大写; 因没有全局阅读代码,我现在是临时将 lockdos去重这里统一转大写进行判断去重了;怕有没看到的其他代码部分有啥问题 比如:io.seata.server.session.BranchSession#setLockKey这个方法中的表名,这个lockkey不知道都哪里用了,大小写不一致是否有问题,还请咱们seata了解的人员整体检查一遍 这个截图里是存到lock_table中的row_key中的表名有实际业务sql中的表名的大小写决定了 另外LockStoreDataBaseDAO中 String checkLockSQL = LockStoreSqlFactory.getLogStoreSql(dbType).getCheckLockableSql(lockTable, lockDOs.size());这个查询也可能因mysql 字段值不区分大小写,oracle区分大小写会有差异,from lock_table where row_key IN() row_key中表名的大小写,主键值的大小写,会影响查询到的结果,这个是否有印象我没细致考虑
目前自行修改源码后在客户uat环境已经测试验证通过,未修改源码 前这个bug是必然触发的
另外在问下官方kingbase人大金仓的支持会随2.1.0发布吗?目前我们着急用,没办法了在2.0.0上自己改出了一个支持人大金仓的;但是后来遇到了2.0.0回滚回退顺序的bug问题,还没来得及再把人大金仓的支持移到1.8.0上
还有这个大小写导致lockDOs去重失败的问题能赶上随2.1.0一块发布吗
@funky-eyes Please assign to me, I will fix this.
发现存在问题的seata版本有2.0.0和1.8.0 同一个全局事务中,不同的分支事务操作同一条记录,锁重入后,lockDOs因lock_table.row_key中表名大小写问题去重失败,导致分支事务报LockWaitTimeoutException: Global lock wait timeout,LockConflictException: get global lock fail, xid,server端报Global lock acquire failed; 原因是:AbstractLocker中protected String getRowKey(String resourceId, String tableName, String pk) { return new StringBuilder().append(resourceId).append(LOCK_SPLIT).append(tableName).append(LOCK_SPLIT).append(pk) .toString(); }的表名应该是来自与sql语句,sql语句中的表名大小写决定了rowKey中表名的大小写;导致如果同一个全局事务中不同分支事务间修改同一条记录时表名有的大写有的小写,导致 LockStoreDataBaseDAO中 // If the lock has been exists in db, remove it from the lockDOs if (CollectionUtils.isNotEmpty(dbExistedRowKeys)) { unrepeatedLockDOs = lockDOs.stream().filter(lockDO -> !dbExistedRowKeys.contains(lockDO.getRowKey())) .collect(Collectors.toList()); } 这里去重失败
建议row_key中的表名统一转为大写;比如在AbstractLocker.getRowKey中将表名转大写; 因没有全局阅读代码,我现在是临时将 lockdos去重这里统一转大写进行判断去重了;怕有没看到的其他代码部分有啥问题 比如:io.seata.server.session.BranchSession#setLockKey这个方法中的表名,这个lockkey不知道都哪里用了,大小写不一致是否有问题,还请咱们seata了解的人员整体检查一遍 这个截图里是存到lock_table中的row_key中的表名有实际业务sql中的表名的大小写决定了 另外LockStoreDataBaseDAO中 String checkLockSQL = LockStoreSqlFactory.getLogStoreSql(dbType).getCheckLockableSql(lockTable, lockDOs.size());这个查询也可能因mysql 字段值不区分大小写,oracle区分大小写会有差异,from lock_table where row_key IN() row_key中表名的大小写,主键值的大小写,会影响查询到的结果,这个是否有印象我没细致考虑
目前自行修改源码后在客户uat环境已经测试验证通过,未修改源码 前这个bug是必然触发的