EggBornJS提供了更便利的数据库事务
支持,下面我们看看在EggJS
和EggBornJS
中,分别是如何支持数据库事务
的
EggJS事务处理方式
- 1const conn = await app.mysql.beginTransaction(); // 初始化事务
- 2
- 3try {
- 4 await conn.insert(table, row1); // 第一步操作
- 5 await conn.update(table, row2); // 第二步操作
- 6 await conn.commit(); // 提交事务
- 7} catch (err) {
- 8 // error, rollback
- 9 await conn.rollback(); // 一定记得捕获异常后回滚事务!!
- 10 throw err;
- 11}
EggBornJS事务处理方式
在EggBornJS中,访问数据库相关的代码不用做任何变更,仅需在API路由上声明启用中间件transaction
即可
src/suite-vendor/test-party/modules/test-party/backend/src/routes.js
- 1// test
- 2{ method: 'post', path: 'kitchen-sink/guide/echo8', controller: testKitchensinkGuide, middlewares: 'transaction' },
不论使用
ctx.db
对象还是model
对象操作数据库,当开启中间件transaction
时,会自动在上下文环境中保持同一个数据库连接,从而便利的支持数据库事务
后端API路由调用链
前面提到,在后端API路由
中可以通过ctx.performAction
调用另一个API路由
,从而形成API路由
调用链
由于每个API路由
都可以单独指定中间件transaction
,那么在API路由
调用链中,transaction
的运作规则是怎样的呢?
基本规则
- 在一个
API路由
调用链中最多只开启一个transaction
,也就是没有子transaction
或嵌套transaction
的概念 - 当前面的
API路由
已开启transaction
时,后面的API路由
不论是否设置了中间件transaction
,都自动处于前面已开启的transaction
当中
规则速查表
如果是主API路由
通过ctx.performAction
调用子API路由
,transaction
开启规则如下:
主API路由配置 |
子API路由配置 |
子API路由实际启用 |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
事务后执行
在一些特殊的场景,需要在当前数据库事务提交
后执行代码逻辑。这时,可以通过ctx.tail
方法登记一个异步方法,此异步方法会在当前数据库事务提交
后自动执行
src/suite-vendor/test-party/modules/test-party/backend/src/controller/test/ctx/tail.js
- 1const require3 = require('require3');
- 2const assert = require3('assert');
- 3
- 4module.exports = app => {
- 5
- 6 class TailController extends app.Controller {
- 7
- 8 async tail() {
- 9 // 1
- 10 this.ctx.meta._cache = 1;
- 11
- 12 // tail
- 13 this.ctx.tail(() => {
- 14 assert.equal(this.ctx.meta._cache, 2);
- 15 });
- 16
- 17 // 2
- 18 this.ctx.meta._cache = 2;
- 19
- 20 // done
- 21 this.ctx.success();
- 22 }
- 23
- 24 }
- 25
- 26 return TailController;
- 27};
评论: