13.4. Data Consistency Checks at the Application Level | ||||
---|---|---|---|---|
Prev | Up | Chapter 13. Concurrency Control | Home | Next |
13.4. Data Consistency Checks at the Application Level#
It is very difficult to enforce business rules regarding data integrity using Read Committed transactions because the view of the data is shifting with each statement, and even a single statement may not restrict itself to the statement's snapshot if a write conflict occurs.
While a Repeatable Read transaction has a stable view of the data throughout its execution, there is a subtle issue with usingMVCC snapshots for data consistency checks, involving something known asread/write conflicts. If one transaction writes data and a concurrent transaction attempts to read the same data (whether before or after the write), it cannot see the work of the other transaction. The reader then appears to have executed first regardless of which started first or which committed first. If that is as far as it goes, there is no problem, but if the reader also writes data which is read by a concurrent transaction there is now a transaction which appears to have run before either of the previously mentioned transactions. If the transaction which appears to have executed last actually commits first, it is very easy for a cycle to appear in a graph of the order of execution of the transactions. When such a cycle appears, integrity checks will not work correctly without some help. As mentioned inSection 13.2.3, Serializable transactions are just Repeatable Read transactions which add nonblocking monitoring for dangerous patterns of read/write conflicts. When a pattern is detected which could cause a cycle in the apparent order of execution, one of the transactions involved is rolled back to break the cycle. If the Serializable transaction isolation level is used for all writes and for all reads which need a consistent view of the data, no other effort is required to ensure consistency. Software from other environments which is written to use serializable transactions to ensure consistency should“just work” in this regard inPostgreSQL. When using this technique, it will avoid creating an unnecessary burden for application programmers if the application software goes through a framework which automatically retries transactions which are rolled back with a serialization failure. It may be a good idea to set SeeSection 13.2.3 for performance suggestions. This level of integrity protection using Serializable transactions does not yet extend to hot standby mode (Section 26.4) or logical replicas. Because of that, those using hot standby or logical replication may want to use Repeatable Read and explicit locking on the primary. When non-serializable writes are possible, to ensure the current validity of a row and protect it against concurrent updates one must use Also of note to those converting from other environments is the fact that13.4.1. Enforcing Consistency with Serializable Transactions#
default_transaction_isolation
toserializable
. It would also be wise to take some action to ensure that no other transaction isolation level is used, either inadvertently or to subvert integrity checks, through checks of the transaction isolation level in triggers.Warning: Serializable Transactions and Data Replication
13.4.2. Enforcing Consistency with Explicit Blocking Locks#
SELECT FOR UPDATE
,SELECT FOR SHARE
, or an appropriateLOCK TABLE
statement. (SELECT FOR UPDATE
andSELECT FOR SHARE
lock just the returned rows against concurrent updates, whileLOCK TABLE
locks the whole table.) This should be taken into account when porting applications toPostgreSQL from other environments.SELECT FOR UPDATE
does not ensure that a concurrent transaction will not update or delete a selected row. To do that inPostgreSQL you must actually update the row, even if no values need to be changed.SELECT FOR UPDATE
temporarily blocks other transactions from acquiring the same lock or executing anUPDATE
orDELETE
which would affect the locked row, but once the transaction holding this lock commits or rolls back, a blocked transaction will proceed with the conflicting operation unless an actualUPDATE
of the row was performed while the lock was held.