[seata]seata 1.5.2使用mybatis-plus插入 lock_table主键重复 Duplicate entry

2023-12-19 373 views
7

Ⅰ. Issue Description 1.4.2 升1.5.2 使用mybatis-plus-boot-starter 自用生成的insert插入后发现lock_table主键冲突 debug后发现 lock_table生成的row_key重复 并且对应的brancher_id的undo_log的分支事务生成了一条重复的数据

Ⅱ. Describe what happened

image image

server端主键冲突 ava.sql.BatchUpdateException: Duplicate entry 'jdbc:mysql://dev.db.yelopack.com:3306/dev_yelolife_basicdata^^^t' for key 'PRIMARY' at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1607) at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1272) at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeBatch(DruidPooledPreparedStatement.java:565) at io.seata.server.storage.db.lock.LockStoreDataBaseDAO.doAcquireLocks(LockStoreDataBaseDAO.java:368) at io.seata.server.storage.db.lock.LockStoreDataBaseDAO.acquireLock(LockStoreDataBaseDAO.java:186) at io.seata.server.storage.db.lock.DataBaseLocker.acquireLock(DataBaseLocker.java:64) at io.seata.server.lock.AbstractLockManager.acquireLock(AbstractLockManager.java:65) at io.seata.server.session.BranchSession.lock(BranchSession.java:287) at io.seata.server.transaction.at.ATCore.branchSessionLock(ATCore.java:80) at io.seata.server.coordinator.AbstractCore.lambda$branchRegister$0(AbstractCore.java:83) at io.seata.server.storage.db.session.DataBaseSessionManager.lockAndExecute(DataBaseSessionManager.java:191) at io.seata.server.session.SessionHolder.lockAndExecute(SessionHolder.java:365) at io.seata.server.coordinator.AbstractCore.branchRegister(AbstractCore.java:77) at io.seata.server.coordinator.DefaultCore.branchRegister(DefaultCore.java:102) at io.seata.server.coordinator.DefaultCoordinator.doBranchRegister(DefaultCoordinator.java:277) at io.seata.server.AbstractTCInboundHandler$4.execute(AbstractTCInboundHandler.java:184) at io.seata.server.AbstractTCInboundHandler$4.execute(AbstractTCInboundHandler.java:179) at io.seata.core.exception.AbstractExceptionHandler.exceptionHandleTemplate(AbstractExceptionHandler.java:131) at io.seata.server.AbstractTCInboundHandler.handle(AbstractTCInboundHandler.java:179) at io.seata.core.protocol.transaction.BranchRegisterRequest.handle(BranchRegisterRequest.java:136) at io.seata.server.coordinator.DefaultCoordinator.onRequest(DefaultCoordinator.java:511) at io.seata.core.rpc.processor.server.ServerOnRequestProcessor.handleRequestsByMergedWarpMessage(ServerOnRequestProcessor.java:285) at io.seata.core.rpc.processor.server.ServerOnRequestProcessor.onRequestMessage(ServerOnRequestProcessor.java:196) at io.seata.core.rpc.processor.server.ServerOnRequestProcessor.process(ServerOnRequestProcessor.java:123) at io.seata.core.rpc.netty.AbstractNettyRemoting.lambda$processMessage$2(AbstractNettyRemoting.java:281) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.lang.Thread.run(Unknown Source) Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'jdbc:mysql://dev.db.yelopack.com:3306/dev_yelolife_basicdata^^^t' for key 'PRIMARY' at sun.reflect.GeneratedConstructorAccessor38.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) at java.lang.reflect.Constructor.newInstance(Unknown Source) at com.mysql.jdbc.Util.handleNewInstance(Util.java:389) at com.mysql.jdbc.Util.getInstance(Util.java:372) at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:973) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3835) at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3771) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2435) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2582) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2535) at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1911) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2145) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2081) at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2066) at com.mysql.jdbc.PreparedStatement.executeBatchedInserts(PreparedStatement.java:1568) ... 28 common frames omitted

Ⅵ. Environment:
  • JDK version :
  • jdk alibaba 11
  • Seata version: 1.5.2
  • OS : linux
  • Others:

回答

4

在一个事务里先删除后添加了吧?

3

你上面这个rowkey怎么插入2条的,这是主键,直接抛异常的

5

单纯的insert 同一个pk,你这个事务不提交,另一个本地事务不可能insert这条相同pk的数据 和 申请全局锁 a事务insert pk=57 再插入全局锁 b事务insert pk肯定不是57了

5

我把lock_table主键约束去了,才发现的两条数据, 并不是先删除后插入,只是简单的insert , a服务调用B服务 版本是alibaba的2021.0.4.0 回退至seata1.4.2后 lock_table 3条变为2条了正常了lock_table重复数据没了

3

你的57被另一个事务占了呀,当然抢不到了,1.4.2是先检查锁是否存在,所以不会有主键冲突的异常,1.6上会修掉,出现主键冲突后会再查一下,避免抛异常

5

还有个问题,你pk是57,说明前一个事务也执行了insert pk为57的数据,为什么你当前事务pk也是57?client侧肯定会插入失败,你有sample能复现提供一下吗?

2

有2个branchid,同属一个xid,看起来就是2次事务insert了同一条数据,以前可能是因为有锁重入所以无影响,麻烦提供一个sample看下