You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测SQLite异步事务函数是否存在同层级并行调用

如何检测SQLite异步事务函数是否存在同层级并行调用

我写了一个处理SQLite事务的异步函数,它支持嵌套调用——也就是在done回调里可以再次调用transaction(),代码如下:

async transaction<V>(done: (conn: this) => V): Promise<V> {
  this.depth += 1;
  await this.execute(`SAVEPOINT tt_${this.depth}`);
  try {
    return await done(this);
  } catch (err) {
    await this.execute(`ROLLBACK TO tt_${this.depth}`);
    throw err;
  } finally {
    await this.execute(`RELEASE tt_${this.depth}`);
    this.depth -= 1;
  }
}

但这个函数不支持同层级的并行调用,比如用Promise.all同时触发多个事务:

Promise.all([
   db.transaction(...),
   db.transaction(...),
]);

这种情况会打乱SQLite的保存点和释放逻辑。实际场景里,当多个请求同时到达服务器,且都复用同一个db实例时,就会出现这种并行调用的问题。

我当时的疑问是:有没有办法在这个transaction函数内部检测,是否有同层级的函数调用正在并行执行?


后来我自己折腾出了一个用包装类实现的方案,分享给大家:

核心思路是用一个外层包装类来管理事务的执行队列,确保同一时间只有一个同层级的事务在运行,嵌套的事务则不受影响。代码如下:

class DbInstance{
  private depth = 0;
   
  // 这里是原有的数据库操作方法,比如execute等
  // ....
  async transaction<V>(done: (conn: this) => V): Promise<V> {
    this.depth += 1;
    await this.execute(`SAVEPOINT tt_${this.depth}`);
    try {
      return await done(this);
    } catch (err) {
      await this.execute(`ROLLBACK TO tt_${this.depth}`);
      throw err;
    } finally {
      await this.execute(`RELEASE tt_${this.depth}`);
      this.depth -= 1;
    }
  }

}

class Db{
  private dbInstance: DbInstance;
  private activeTrans?: Promise<any>;
  
  constructor(){
    this.dbInstance = new DbInstance();
  }

  async transaction<T>(done: (conn: DbInstance) => Promise<T>): Promise<T> {
    // 如果当前有同层级事务在执行,等待它完成后再递归调用自身
    if(this.activeTrans){
      await this.activeTrans;
      return this.transaction(done);
    }

    // 标记当前有活跃的同层级事务
    this.activeTrans = this.dbInstance.transaction(done);

    try{
      return await this.activeTrans;
    }catch(err){
      throw err;
    }finally{
      // 事务完成后清除标记
      this.activeTrans = undefined;
    }
  }

}

export const db = new Db();

方案说明:

  • 对外暴露的是Db类的实例db,所有事务请求都通过它的transaction方法发起;
  • 内部用activeTrans变量跟踪当前是否有同层级的事务在执行,如果有就等待它完成再处理下一个;
  • 实际的事务逻辑还是由DbInstance类处理,它的depth变量只负责管理嵌套事务的保存点,不受并行请求影响;
  • 嵌套事务可以正常工作,因为在done回调里传入的是DbInstance的实例,在里面调用transaction()只会修改它自己的depth,不会触发外层的排队逻辑。

小缺点:

这个方案需要让Db和DbInstance两个类实现相同的数据库操作方法,会有一些重复代码,但整体完美解决了同层级并行调用的问题。


备注:内容来源于stack exchange,提问作者Alex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 10:19:35