2.7. Transactions

A transaction is used to interact with the data in a database. Whenever data is read or written to the database it is done by using a transaction.

Transactions offer some protection from application and system failures. A transaction may be used to store multiple data records or to conditionally modify certain data records. A transaction represents an atomic and durable set of data access and data mutation operations.

All transactions are created through a connection, which is the transaction’s connection.

A transaction has a scope which is a set of object stores that the transaction may interact with. A transaction’s scope remains fixed for the lifetime of that transaction.

Two transactions have overlapping scope if any object store is in both transactions’ scope.

A transaction has a mode that determines which types of interactions can be performed upon that transaction. The mode is set when the transaction is created and remains fixed for the life of the transaction. A transaction‘s mode is one of the following:

["readonly"](#dom-idbtransactionmode-readonly)

The transaction is only allowed to read data. No modifications can be done by this type of transaction. This has the advantage that several read-only transactions can run at the same time even if their scopes are overlapping, i.e. if they are using the same object stores. This type of transaction can be created any time once a database has been opened.

["readwrite"](#dom-idbtransactionmode-readwrite)

The transaction is allowed to read, modify and delete data from existing object stores. However object stores and indexes can’t be added or removed. Multiple ["readwrite"](#dom-idbtransactionmode-readwrite) transactions can’t run at the same time if their scopes are overlapping since that would mean that they can modify each other’s data in the middle of the transaction. This type of transaction can be created any time once a database has been opened.

["versionchange"](#dom-idbtransactionmode-versionchange)

The transaction is allowed to read, modify and delete data from existing object stores, and can also create and remove object stores and indexes. It is the only type of transaction that can do so. This type of transaction can’t be manually created, but instead is created automatically when an upgradeneeded event is fired.

A transaction has a durability hint. This is a hint to the user agent of whether to prioritize performance or durability when committing the transaction. The durability hint is one of the following:

["strict"](#dom-idbtransactiondurability-strict)

The user agent may consider that the transaction has successfully committed only after verifying that all outstanding changes have been successfully written to a persistent storage medium.

["relaxed"](#dom-idbtransactiondurability-relaxed)

The user agent may consider that the transaction has successfully committed as soon as all outstanding changes have been written to the operating system, without subsequent verification.

["default"](#dom-idbtransactiondurability-default)

The user agent should use its default durability behavior for the storage bucket. This is the default for transactions if not otherwise specified.

In a typical implementation, ["strict"](#dom-idbtransactiondurability-strict) is a hint to the user agent to flush any operating system I/O buffers before a ["complete"](#eventdef-transaction-complete) event is fired. While this provides greater confidence that the changes will be persisted in case of subsequent operating system crash or power loss, flushing buffers can take significant time and consume battery life on portable devices.

Web applications are encouraged to use ["relaxed"](#dom-idbtransactiondurability-relaxed) for ephemeral data such as caches or quickly changing records, and ["strict"](#dom-idbtransactiondurability-strict) in cases where reducing the risk of data loss outweighs the impact to performance and power. Implementations are encouraged to weigh the durability hint from applications against the impact to users and devices.

A transaction optionally has a cleanup event loop which is an event loop.

A transaction has a request list of pending requests which have been made against the transaction.

A transaction has a error which is set if the transaction is aborted.

A transaction‘s get the parent algorithm returns the transaction’s connection.

A read-only transaction is a transaction with mode ["readonly"](#dom-idbtransactionmode-readonly).

A read/write transaction is a transaction with mode ["readwrite"](#dom-idbtransactionmode-readwrite).

2.7.1. Transaction lifecycle

A transaction has a state, which is one of the following:

active

A transaction is in this state when it is first created, and during dispatch of an event from a request associated with the transaction.

New requests can be made against the transaction when it is in this state.

inactive

A transaction is in this state after control returns to the event loop after its creation, and when events are not being dispatched.

No requests can be made against the transaction when it is in this state.

committing

Once all requests associated with a transaction have completed, the transaction will enter this state as it attempts to commit.

No requests can be made against the transaction when it is in this state.

finished

Once a transaction has committed or aborted, it enters this state.

No requests can be made against the transaction when it is in this state.

Transactions are expected to be short lived. This is encouraged by the automatic committing functionality described below.

Authors can still cause transactions to run for a long time; however, this usage pattern is not advised as it can lead to a poor user experience.

The lifetime of a transaction is as follows:

  1. A transaction is created with a scope and a mode. When a transaction is created its state is initially active.

  2. When an implementation is able to enforce the constraints for the transaction’s scope and mode, defined below, the implementation must queue a task to start the transaction asynchronously.

    Once the transaction has been started the implementation can begin executing the requests placed against the transaction. Requests must be executed in the order in which they were made against the transaction. Likewise, their results must be returned in the order the requests were placed against a specific transaction. There is no guarantee about the order that results from requests in different transactions are returned.

    Transaction modes ensure that two requests placed against different transactions can execute in any order without affecting what resulting data is stored in the database.

  3. When each request associated with a transaction is processed, a success or error event will be fired. While the event is being dispatched, the transaction state is set to active, allowing additional requests to be made against the transaction. Once the event dispatch is complete, the transaction’s state is set to inactive again.

  4. A transaction can be aborted at any time before it is finished, even if the transaction isn’t currently active or hasn’t yet started.

    An explicit call to [abort()](#dom-idbtransaction-abort) will initiate an abort. An abort will also be initiated following a failed request that is not handled by script.

    When a transaction is aborted the implementation must undo (roll back) any changes that were made to the database during that transaction. This includes both changes to the contents of object stores as well as additions and removals of object stores and indexes.

  5. The implementation must attempt to commit a transaction when all requests placed against the transaction have completed and their returned results handled, no new requests have been placed against the transaction, and the transaction has not been aborted

    An explicit call to [commit()](#dom-idbtransaction-commit) will initiate a commit without waiting for request results to be handled by script.

    When committing, the transaction state is set to committing. The implementation must atomically write any changes to the database made by requests placed against the transaction. That is, either all of the changes must be written, or if an error occurs, such as a disk write error, the implementation must not write any of the changes to the database, and the steps to abort a transaction will be followed.

  6. When a transaction is committed or aborted, its state is set to finished.

The implementation must allow requests to be placed against the transaction whenever it is active. This is the case even if the transaction has not yet been started. Until the transaction is started the implementation must not execute these requests; however, the implementation must keep track of the requests and their order.

To cleanup Indexed Database transactions, run the following steps. They will return true if any transactions were cleaned up, or false otherwise.

  1. If there are no transactions with cleanup event loop matching the current event loop, return false.

  2. For each transaction transaction with cleanup event loop matching the current event loop:

    1. Set transaction’s state to inactive.

    2. Clear transaction’s cleanup event loop.

  3. Return true.

This behavior is invoked by [HTML]. It ensures that transactions created by a script call to [transaction()](#dom-idbdatabase-transaction) are deactivated once the task that invoked the script has completed. The steps are run at most once for each transaction.

An event with type complete is fired at a transaction that has successfully committed.

An event with type abort is fired at a transaction that has aborted.

2.7.2. Transaction scheduling

The following constraints define when a transaction can be started:

Implementations may impose additional constraints. For example, implementations are not required to run non-overlapping read/write transactions in parallel, or may impose limits on the number of running transactions.

These constraints imply the following:

2.7.3. Upgrade transactions

An upgrade transaction is a transaction with mode ["versionchange"](#dom-idbtransactionmode-versionchange).

An upgrade transaction is automatically created when running the steps to run an upgrade transaction after a connection is opened to a database, if a version greater than the current version is specified. This transaction will be active inside the upgradeneeded event handler.

An upgrade transaction enables the creation, renaming, and deletion of object stores and indexes in a database.

An upgrade transaction is exclusive. The steps to open a database ensure that only one connection to the database is open when an upgrade transaction is running. The upgradeneeded event isn’t fired, and thus the upgrade transaction isn’t started, until all other connections to the same database are closed. This ensures that all previous transactions are finished. As long as an upgrade transaction is running, attempts to open more connections to the same database are delayed, and any attempts to use the same connection to start additional transactions by calling [transaction()](#dom-idbdatabase-transaction) will throw an exception. Thus upgrade transactions not only ensure that no other transactions are running concurrently, but also ensure that no new transactions are queued against the same database as long as the transaction is running.

This ensures that once an upgrade transaction is complete, the set of object stores and indexes in a database remain constant for the lifetime of all subsequent connections and transactions.