跳到主要内容

withTriggersDisabled()

function withTriggersDisabled<T>(
adapter,
tx,
body
): Promise<T>;

Defined in: packages/rxdb-adapter-sqlite-core/src/version/with_triggers_disabled.ts:88

在触发器停用的窗口内执行一段写入:删触发器 → 跑 body → 重建触发器。

Type Parameters​

Type Parameter
T

Parameters​

ParameterTypeDescription
adapterRxDBAdapterSqliteBaseSQLite 适配器
txSqlExecutor当前事务的执行器;三明治的三步必须落在同一事务里
body() => Promise<T>窗口内要执行的写入,返回值原样透传

Returns​

Promise<T>

body 的返回值

Throws​

原样重抛 body 的错误——body 抛错但触发器重建成功时

Throws​

RxDBAdapterSqliteError 触发器重建阶段读不到当前分支时抛出(不论 body 是否成功,见下)

Throws​

AggregateError body 与触发器重建都失败时抛出:errors 为 [bodyError, restoreError],cause 为 bodyError

Remarks​

用于「把远端副本抄进本地表」的路径:拉取回填与 QueryCache 的缓存写入都不是本地变更, 不该进 rxdb_change。表上的 AFTER INSERT/UPDATE/DELETE 触发器不区分写入来源, 唯一的抑制手段就是在写入期间把它们摘掉。

三步必须与写入同事务:拆成两次 runInTransaction 会在 C2 嵌套事务下自死锁 (见 readCurrentBranchId 的说明),而且中间那个没有触发器的已提交窗口会对并发写敞开 —— 那些写入的历史将永久丢失。

重建复用 generateSwitchBranchSql("切到当前分支"),因此它捎带的分支表 UPDATE 是 恒等写:RxDBBranch 自身 log: false,不会因此产生变更行。

重建触发器是「不论成功失败都必须跑」的收尾,且不用 try/finally 实现:本函数的生产 调用点都在 this.transaction() 里,body 抛错时整个事务连带回滚,中间那个「触发器已删、 还没重建」的状态从未真正提交过;但本函数经 src/index.ts 公开导出,第三方在事务外调用、 body 抛错时,这个中间态是真实会提交的——库从此永久没有触发器,且没有任何报错提示。 若改用 try { ... } finally { await restoreTriggers(); },finally 块里一旦再抛错 (重建本身失败),会按 no-unsafe-finally 描述的语义吞掉 try 块的完成状态, body 的原始错误就此彻底消失、无迹可寻。这里改用「先捕获 body 的结果,再无条件跑一遍 收尾,最后按两者结果决定抛什么」的写法:与 packages/rxdb-test/src/encrypted/temporary-value.ts 的 withTemporaryValue 同构 ——该函数解决的是结构相同的问题(跑主操作 → 无条件跑一个「必须执行」的收尾 → 两个都失败时用 AggregateError 保留两边),这里直接沿用同一套形状与措辞风格。

Example​

await adapter.runInTransaction(
tx => withTriggersDisabled(adapter, tx, () => writeRemoteRows(tx, rows)),
false
);