只要您使用适当的 IDBTransaction,是否可以从单个事务中完成所有这些操作,而不是打开多个事务(读取表、写入表、写入另一个表等)?
Mozilla 说:“保持事务活跃的唯一方法是对其发出请求。请求完成后,您将收到一个 DOM 事件,并且假设请求成功,您将有另一个机会来扩展事务该回调期间的交易。”这有点模糊。这是否意味着如果我为 DOM 回调提供一个事件处理程序,我可以在该回调中的任何点使用该事务,而不必担心事务被关闭?
https://developer.mozilla.org/en/IndexedDB/Using_IndexedDB#Adding_data_to_the_database
简短的回答:如果您为“成功”或“错误”事件提供一个事件处理程序,您可以在该事件处理程序中放置一个新请求,而不必担心事务会自动关闭。
长答案:事务提交通常应该是完全透明的。唯一的规则是,在执行非数据库“操作”时不能保持事务打开。 IE。您无法启动事务,然后在执行某些 XMLHttpRequest 时或等待用户单击按钮时将其保持打开状态。
一旦您停止对交易发出请求并且最后一个请求回调完成,交易就会自动关闭。
但是,您可以启动一个事务,使用该事务读取一些数据,然后写入一些结果。
因此,请确保在开始事务之前拥有所需的所有数据,然后在请求回调中执行您想要执行的所有读取和写入操作。完成后交易将自动完成。
IndexedDB 事务在最后一个回调被触发后立即提交,因此保持它们存活的方法是通过回调传递它们。
我从 Jonas Sicking 那里获取交易信息,Jonas Sicking 是 Mozilla 开发人员和 IndexedDB 的联合规范编写者,他对 这篇优秀的博客文章 发表了以下评论:
以下句子不正确“今日交易自动提交” 当事务变量超出范围且不再有请求时 可以靠着它放置”。
当变量超出时,事务永远不会自动提交 范围。一般来说,他们只在最后一次成功/错误回调时提交 触发并且该回调不会安排更多请求。所以这不是 与任何变量的范围有关。
唯一的例外是,如果您创建了交易但没有放置 反对它的请求。在这种情况下,交易被“提交” (无论这对于没有请求的交易意味着什么)尽快 当您返回事件循环时。在这种情况下你可以 一旦所有提及交易,技术上就“提交”交易 超出了范围,但这并不是一个特别有趣的用例 优化。
简短回答:不要保留。
为了防止竞争条件,IndexedDB 是为隐式提交而设计的,因此您不能显式地保持事务处于活动状态。如果需要,请更改您的算法,以便不需要保持其活动状态。
重用事务以提高性能并执行有序请求。在这些情况下,事务将隐式保持活动状态。
要保持事务活跃,请继续执行完成操作的回调中的下一个操作。请参考以下示例代码。
function put_data(db,tableName,data_array)
{
var objectStore=db.transaction([tableName],"readwrite").objectStore(tableName);
put_record(data_array,objectStore,num_rows,0);
}
function put_record(data_array,objectStore,row_index)
{
if(row_index<data_array.length)
{
var req=objectStore.put(data_array[row_index]);
req.onsuccess=function(e)
{
row_index+=1;
put_record(data_array,objectStore,row_index);
};
req.onerror = function()
{
console.error("error", this.error);
row_index+=1;
put_record(data_array,objectStore,row_index);
};
}
}
使用以下方法大约需要 0.5 毫秒,可以检查交易是否存活/可用:
export function isIDBTransactionOpen(tx: IDBTransaction): boolean {
try {
tx.objectStore('this-store-should-never-exist');
return true;
} catch (err: any) {
if (err.name === 'NotFoundError' || err.name === 'InvalidStateError') {
return true;
} else {
return false;
}
}
}