seata事务无法回滚, oracle.sql.TIMESTAMP在seata环境下序列化失败, AbstractUndoExecutor - 259] - [msg: Field not equal

[ INFO ] [2021-05-31 10:25:08.575] [thread: rpcDispatch_RMROLE_1_7_16] [io.seata.core.rpc.processor.client.RmBranchRollbackProcessor - 56] - [msg: rm handle branch rollback process:xid=192.168.3.66:8091:142575713164201984,branchId=142575715471069185,branchType=AT,resourceId=jdbc:oracle:thin:@192.168.3.152:49161:XE/YUE,applicationData=null]
[ INFO ] [2021-05-31 10:25:08.575] [thread: rpcDispatch_RMROLE_1_7_16] [io.seata.rm.AbstractRMHandler - 123] - [msg: Branch Rollbacking: 192.168.3.66:8091:142575713164201984 142575715471069185 jdbc:oracle:thin:@192.168.3.152:49161:XE/YUE]
[ INFO ] [2021-05-31 10:25:08.581] [thread: rpcDispatch_RMROLE_1_7_16] [io.seata.rm.datasource.undo.AbstractUndoExecutor - 259] - [msg: Field not equals, name CREATE_TIME, old value 2021-05-31 10:25:02.0, new value 2021-05-31 10:25:02.736]
[ INFO ] [2021-05-31 10:25:08.584] [thread: rpcDispatch_RMROLE_1_7_16] [io.seata.rm.datasource.DataSourceManager - 41] - [msg: branchRollback failed. branchType:[AT], xid:[192.168.3.66:8091:142575713164201984], branchId:[142575715471069185], resourceId:[jdbc:oracle:thin:@192.168.3.152:49161:XE/YUE], applicationData:[null]. reason:[Branch session rollback failed and try again later xid = 192.168.3.66:8091:142575713164201984 branchId = 142575715471069185 Has dirty records when undo.]]
[ INFO ] [2021-05-31 10:25:08.585] [thread: rpcDispatch_RMROLE_1_7_16] [io.seata.rm.AbstractRMHandler - 131] - [msg: Branch Rollbacked result: PhaseTwo_RollbackFailed_Retryable]

其实报错很明显:

AbstractUndoExecutor - 259] - [msg: Field not equals, name CREATE_TIME, old value 2021-05-31 10:25:02.0, new value 2021-05-31 10:25:02.736]

 

 AbstractUndoExecutor 在 事务回滚的时候会比较 之前的镜像和之后的镜像,  如果字段值不匹配, 就会会滚失败.      偏偏遇到 oracle.sql.TIMESTAMP序列化损失精度,  所以不相等.

    protected boolean dataValidationAndGoOn(Connection conn) throws SQLException {

        TableRecords beforeRecords = sqlUndoLog.getBeforeImage();
        TableRecords afterRecords = sqlUndoLog.getAfterImage();

        // Compare current data with before data
        // No need undo if the before data snapshot is equivalent to the after data snapshot.
        Result<Boolean> beforeEqualsAfterResult = DataCompareUtils.isRecordsEquals(beforeRecords, afterRecords);
        if (beforeEqualsAfterResult.getResult()) {
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("Stop rollback because there is no data change " +
                        "between the before data snapshot and the after data snapshot.");
            }
            // no need continue undo.
            return false;
        }

        // Validate if data is dirty.
        TableRecords currentRecords = queryCurrentRecords(conn);
        // compare with current data and after image.
        Result<Boolean> afterEqualsCurrentResult = DataCompareUtils.isRecordsEquals(afterRecords, currentRecords);
        if (!afterEqualsCurrentResult.getResult()) {

            // If current data is not equivalent to the after data, then compare the current data with the before 
            // data, too. No need continue to undo if current data is equivalent to the before data snapshot
            Result<Boolean> beforeEqualsCurrentResult = DataCompareUtils.isRecordsEquals(beforeRecords, currentRecords);
            if (beforeEqualsCurrentResult.getResult()) {
                if (LOGGER.isInfoEnabled()) {
                    LOGGER.info("Stop rollback because there is no data change " +
                            "between the before data snapshot and the current data snapshot.");
                }
                // no need continue undo.
                return false;
            } else {
                if (LOGGER.isInfoEnabled()) {
                    if (StringUtils.isNotBlank(afterEqualsCurrentResult.getErrMsg())) {
                        LOGGER.info(afterEqualsCurrentResult.getErrMsg(), afterEqualsCurrentResult.getErrMsgParams());
                    }
                }
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("check dirty datas failed, old and new data are not equal," +
                            "tableName:[" + sqlUndoLog.getTableName() + "]," +
                            "oldRows:[" + JSON.toJSONString(afterRecords.getRows()) + "]," +
                            "newRows:[" + JSON.toJSONString(currentRecords.getRows()) + "].");
                }
                throw new SQLException("Has dirty records when undo.");
            }
        }
        return true;
    }

 DataCompareUtils.isRecordsEquals(afterRecords, currentRecords);  主要是这个类在比较.

 

找到了 动刀子,  扩展支持 oracle.sql.TIMESTAMP,  抹去精度, 转化为19位日期.

 

这是一种方式,  也可以搞一下 重写一个 UndoLogParser,  另一种方式, 你们自行搞吧.

   

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值