工作关键点总结


前言

项目关键点进行复盘

项目关键点:iris,yms,yts,并发

一、事务管理器,写锁阻塞,事务传播机制

参考资料:结合Spring事务源码分析TransactionSynchronizationAdapter之afterCommit回调方法事务回滚问题.

1.业务演变过程:

代码逻辑:
try {
	1.更新本地单据数据,本地写操作
	2.rpc调用远程接口,跨服务写操作
	3.发事件到mq,可靠消息保证跨领域分布式事务
} catch {
	4.抓异常
	5.更新单据为生效失败状态,本地写事务提交
}

场景复盘:这是审批流程的部分代码,业务希望无论如何要使审批流程正常走完,即便try代码块中有调用失败,也要在catch中吞掉异常,并记录失败状态,走补偿机制(重新执行或定时任务接口)
try中2远程写操作封装在另一service业务类中,该类标记@Transactional注解,事务传播属性为默认required。

问题出现:该service中的异常未处理,向上抛出。因spring管理的声明式事务是基于aop实现的,该事务在切入时,默认加入外层的当前主事务,在逻辑异常时将事务已标记回滚,回到主类。而主类catch住异常,走5本地写提交时发现,事务已被标记为回滚,主事务无法正常提交,报出rollback only异常。

场景终态:流程抛出rollback only异常,只要业务报错就走不下去,数据永远回滚,生效失败状态永远不会出现。

2.业务改进:

以上异常问题在主子类对事务处理不一致导致,未能满足业务要求,遂想出改进方案:

①.让事务提交:service子类中不抛出异常,而是catch异常封装一个result携带异常信息返回,走事务提交逻辑(注意:如未进行rpc调用则直接返回异常result,已rpc远程写则需要考虑分布式事务问题,回滚远端数据)。但是此方案需要改动其他service类逻辑,不采用。

②.让主事务回滚,再开一个新事务处理生效失败标记操作,可尝试改动

catch {
	1.抓异常
	2.更新单据为生效失败状态,本地写事务提交(在新事务中完成此操作)
	3.抛出封装后的业务异常
}

操作:catch块中抛异常 让主事务也回滚,然后新开事务来处理失败标记场景
执行2更新单据为生效失败方法的事务传播属性改为required_new
之前学习中,可以看到很多弱一致性或不加入事务的写操作可采用这种方法,标记为required_new后,新开事务,在自己的事务中执行业务并提交事务,使之互不干扰。但此场景下依然有问题

问题出现: 依然失败,报错数据库写锁阻塞。之前的学习中,本事务和新开事务一般操作的为不相干的数据,二者互不影响。但此事务中,try块里1操作写本地事务,占用着本条数据行,事务还未结束。catch中开启新事务操作同一行数据,造成数据库写锁阻塞,造成死锁。

3.再次方案改进

复盘之前方案:1中问题是主子事务操作不一致,则2改进点为将二者变为一致,新开事务进行改状态。2中问题为新旧事务操作同一数据,则改进点为,在本事务结束,或者说数据落盘之后(connection.commit()方法执行后),再进行标记生效失败操作。可以想到事务同步回调机制方案,尝试改动:

catch {
	1.回调方法,在当前事务结束时调用(更新单据为生效失败状态,本地写事务提交)
	2.抓异常
	3.抛出封装后的业务异常
}

操作: catch中抛出异常,让主事务也回滚(和2一样),然后利用同步机制,在主事务结束时触发回调机制
TransactionSynchronizationManager.registerSynchronization机制 TransactionSynchronizationAdapter的回调方法afterCompletion(此时事务回滚已落盘,所以回调机制成功与否不影响本次事务的提交与回滚)来执行更新单据为生效失败状态操作

catch (Exception e) {
    afterTransactionCompletion(id);
    throw new RuntimeException(e.getMessage(),e);
}

private void afterTransactionCompletion(String id) {
        if (TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCompletion(int status) {
                    if (status == 1) {
                        //修改单据为生效失败
                    }
                }
            });
        }
    }

(额外:若回调方法也有一系列操作,其中如果有异常场景:当回调操作中service的propagation = Propagation.REQUIRES_NEW时,已执行的部分事务会回滚;当propagation = Propagation.REQUIRED时,已执行的部分事务不会回滚)。

二、并发线程管理

1.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值