Transaction

2018-11-23 09:08:45

EggBorn提供了更便利的数据库事务支持,下面我们看看在EggJSEggBorn中,分别是如何支持数据库事务

EggJS事务处理方式

const conn = await app.mysql.beginTransaction(); // 初始化事务

try {
  await conn.insert(table, row1);  // 第一步操作
  await conn.update(table, row2);  // 第二步操作
  await conn.commit(); // 提交事务
} catch (err) {
  // error, rollback
  await conn.rollback(); // 一定记得捕获异常后回滚事务!!
  throw err;
}

EggBorn事务处理方式

在EggBorn中,访问数据库相关的代码不用做任何变更,仅需在API路由上声明启用中间件transaction即可

src/module/test-todo/backend/src/routes.js

// test
{ method: 'post', path: 'test/echo', controller: test, middlewares: 'transaction' },

不论使用ctx.db对象还是model对象操作数据库,当开启中间件transaction时,会自动在上下文环境中保持同一个数据库连接,从而便利的支持数据库事务

后端API路由调用链

前面提到,在后端API路由中可以通过ctx.performAction调用另一个API路由,从而形成API路由调用链

由于每个API路由都可以单独指定中间件transaction,那么在API路由调用链中,transaction的运作规则是怎样的呢?

基本规则

  1. 在一个API路由调用链中最多只开启一个transaction,也就是没有子transaction嵌套transaction的概念
  2. 当前面的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.dbMeta.next方法登记一个异步方法,此异步方法会在当前数据库事务提交后自动执行

async echo() {
  // insert
  const res = await this.ctx.model.todo.insert({
    atomId: 0,
    description: 'test',
  });
  // next
  this.ctx.dbMeta.next(async () => {
    console.log(res.insertId);
    console.log('Will be invoked after transaction committed');
  });
  this.ctx.success(null);
}


评论: