Node.js微服务跨服务事务处理:创建用户失败时回滚Person记录
跨服务事务实现:创建User失败时回滚已创建的People记录
你的场景是两个服务分别操作数据库:test2服务创建People记录,test服务创建关联该People的User记录,要求User创建失败时,已创建的People能被回滚。但现有代码存在关键问题,导致无法实现预期的回滚效果。
现有代码的问题
test2服务在创建People后直接执行了await t.commit(),这会导致People记录被立即提交到数据库。后续即使test服务创建User失败并触发回滚,已经提交的People记录无法被撤销——因为事务一旦提交就无法回滚。
修正方案
要实现跨服务的事务一致性,必须由事务的发起方(test服务)统一控制事务的提交和回滚,子服务(test2)只在该事务上下文内执行操作,不自行提交事务。
修正后的test服务代码
async test(req, res) { let t = await sequlize.transaction(); try { let rs = await this.getEurekaManager('education'); const instance = this.createAxiosInstance(req.payload); // 传递事务ID给test2服务 let response = await instance.post(rs.homePageUrl + '/api/v1/TermLessons/test2', { firstName: "John", lastName: "Doe" }, {headers: {'Transaction-Id': t.id}}); let person = response.data; // 在同一事务下创建User await model.Users.create({ Username: "johnDoe", PersonId: person.PersonId }, {transaction: t}); // 所有操作成功后,统一提交事务 await t.commit(); res.json("Successfully"); } catch (error) { console.log(error); // 任意步骤失败,回滚整个事务(包括test2创建的People) await t.rollback(); res.json(error); } }
修正后的test2服务代码
async test2(req, res) { try { // 根据传入的事务ID获取已存在的事务对象,而非新建 let t = await sequlize.transaction({id: req.headers['transaction-id'], lock: true}); let person = await model.People.create({ FirstName: req.body.firstName, LastName: req.body.lastName }, { returning: true, transaction: t }); // 不要在此处提交事务,由发起方test服务统一控制 res.json(person); } catch (error) { console.log(error); // 此处无需自行回滚,由发起方统一处理 res.status(500).json(error); } }
关键说明
- 事务的生命周期完全由发起方test服务管理:从创建事务,到协调子服务操作,最后统一提交或回滚。
- test2服务仅在传入的事务上下文内执行创建操作,不提交事务,确保所有操作处于同一个事务边界内。
- 当test服务中任何一步(调用test2、创建User)失败,都会触发整个事务的回滚,包括test2服务创建的People记录。
内容的提问来源于stack exchange,提问作者mohammad tavassolian
相关产品推荐
相关产品推荐

