如何检测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
相关产品推荐
相关产品推荐

