在Seata中,当你在服务方法上使用@GlobalTransactional注解时,Seata会为该全局事务创建一个事务上下文,并在远程服务调用时传递这个事务上下文。Seata客户端会拦截你的Feign调用,并在调用前后进行额外的处理。
以下是Seata如何知道远程服务调用失败并触发全局事务回滚的步骤:
事务上下文传播:当你通过OpenFeign发起远程调用时,Seata会拦截这个调用,并将当前的全局事务XID(事务ID)通过HTTP请求头传递给远程服务。
远程服务拦截:在远程服务端,Seata的拦截器会检查请求头中的XID,并将其绑定到当前的服务线程上下文中,使得远程服务也参与到同一个全局事务中。
异常处理:如果在远程服务的方法执行过程中抛出了异常,Seata的异常处理器会捕获这个异常。
标记事务分支状态:捕获到异常后,Seata会将当前服务的事务分支标记为BranchTransactionStatus.PhaseOne_Failed,这意味着事务分支执行失败。
回滚通知:远程服务会将事务分支的失败状态通知给TC(Transaction Coordinator,事务协调器)。
全局事务回滚决策:TC在接收到事务分支失败的通知后,会根据全局事务的状态和策略来决定是否需要回滚整个全局事务。如果决定回滚,TC会通知所有参与全局事务的服务进行回滚操作。
回滚执行:每个参与的服务收到回滚通知后,会执行本地事务的回滚操作,比如数据库的逆向操作。
在你提供的代码中,如果itemClient.deductStock(detailDTOS);商品服务抛出了异常,注意itemClient.deductStock(detailDTOS);方法本身不抛出异常,是商品服务内部出现异常,以下是可能发生的情况:
如果这个异常没有被捕获,或者被捕获后重新抛出,Seata的拦截器会捕获这个异常。
Seata拦截器会将异常转换为TransactionException,并通知TC当前分支事务失败。
TC根据全局事务的状态,可能会触发全局事务的回滚。
请注意,为了确保Seata能够正确处理异常,你应该确保:
远程服务在捕获异常后,应该将其抛出或者转换为Seata能够识别的异常类型。
你应该配置Seata的异常处理规则,以确保当远程服务返回特定的响应状态码(如500)时,Seata能够将其视为事务失败。