Consistency for simultaneous UPDATES in Oracle, when the WHERE clause depends on the old value The Next CEO of Stack OverflowSQLite - UPSERT *not* INSERT or REPLACEWhat are the options for storing hierarchical data in a relational database?Problem with SQL transaction isolation levelSerializable isolation level in oracleGetting id after insert within a transaction (Oracle)IF statement in Sql query with multiple fieldsWhat's the difference between READ_COMMITTED and SERIALIZABLE isolation levels in Oracle database?Spring transactions and inserting into databaseWhen does Oracle sql exclusively lock a row in an update statement?JPA Lock Mode behaviour
Yu-Gi-Oh cards in Python 3
How to avoid supervisors with prejudiced views?
What CSS properties can the br tag have?
I dug holes for my pergola too wide
Is there such a thing as a proper verb, like a proper noun?
How do I fit a non linear curve?
Aggressive Under-Indexing and no data for missing index
Is French Guiana a (hard) EU border?
Why don't programming languages automatically manage the synchronous/asynchronous problem?
Can I board the first leg of the flight without having final country's visa?
"Eavesdropping" vs "Listen in on"
What flight has the highest ratio of timezone difference to flight time?
Help understanding this unsettling image of Titan, Epimetheus, and Saturn's rings?
Audio Conversion With ADS1243
Does Germany produce more waste than the US?
Won the lottery - how do I keep the money?
Do scriptures give a method to recognize a truly self-realized person/jivanmukta?
Is it okay to majorly distort historical facts while writing a fiction story?
Reshaping json / reparing json inside shell script (remove trailing comma)
Help/tips for a first time writer?
Spaces in which all closed sets are regular closed
Help! I cannot understand this game’s notations!
TikZ: How to fill area with a special pattern?
Players Circumventing the limitations of Wish
Consistency for simultaneous UPDATES in Oracle, when the WHERE clause depends on the old value
The Next CEO of Stack OverflowSQLite - UPSERT *not* INSERT or REPLACEWhat are the options for storing hierarchical data in a relational database?Problem with SQL transaction isolation levelSerializable isolation level in oracleGetting id after insert within a transaction (Oracle)IF statement in Sql query with multiple fieldsWhat's the difference between READ_COMMITTED and SERIALIZABLE isolation levels in Oracle database?Spring transactions and inserting into databaseWhen does Oracle sql exclusively lock a row in an update statement?JPA Lock Mode behaviour
I've been reading about Oracle data consistency guarantees, and supported transaction isolation levels, (e.g. here: https://docs.oracle.com/database/121/CNCPT/consist.htm#CNCPT121) and I feel like I'm getting a lot of high-level information, but I'm not sure how it applies to my specific question.
I'm going to describe a simplified version of my use case, and I'm looking for convincing answers, preferably with references, as to how I need to structure my transaction to get the desired result. (Please don't get too hung up on syntax or data normalization or even data types in my question; it's a straw man -- so if you know what I mean, move on and focus on the concurrency problem.) :)
The Scenario (simplified):
Many users (tens of thousands) are playing an online game simultaneously. Players are all members of two teams, red or blue. Every time a player finishes a game, we want to log the user, their team affiliation, a timestamp, and the score. We also want to aggregate the highest score ever achieved by each team. Our data model looks like this:
// each game is logged in a table that looks kind of like this:
GAMES
time NUMBER,
userid NUMBER,
team NUMBER,
score NUMBER
// high scores are tracked here, assume initial 0-score was inserted at time 0
HIGH_SCORES
team NUMBER,
highscore NUMBER
So, for each score report I receive, I execute a transaction that looks like this
BEGIN
UPDATE HIGH_SCORES set highscore=:1 WHERE team=:2 and :1>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (:1,:2,:3,:4);
COMMIT
The invariant I wish to preserve is that, at any point in time, the high score for each team, as shown in the HIGH_SCORES table will be the highest score I would find if I were to scan the GAMES table and find highscore the hard way.
My understanding of the READ_COMMITED isolation level suggests this won't get me what I want:
Conflicting Writes in Read Committed Transactions
In a read committed transaction, a conflicting write occurs when the transaction attempts to change a row updated by an uncommitted concurrent transaction, sometimes called a blocking transaction. The read committed transaction waits for the blocking transaction to end and release its row lock.
The options are as follows:
If the blocking transaction rolls back, then the waiting transaction proceeds to change the previously locked row as if the other transaction never existed.
If the blocking transaction commits and releases its locks, then the waiting transaction proceeds with its intended update to the newly changed row.
It seems to me that if red team (team 1) has a high score of 100, and two players simultaneously submit better scores, a multithreaded server could have two database transactions going on that begin at the same time:
# Transaction A
UPDATE HIGHSCORES set highscore=150 where team=1 and 150>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (9999,100,1,150);
and
# Transaction B
UPDATE HIGHSCORES set highscore=125 where team=1 and 125>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (9999,101,1,125);
So (In READ_COMMITED mode,) you could get the following sequence: (c.f. Table 9-2 in the Oracle link referenced above)
A updates highscore for red team row; oracle locks this row
B still sees the 100 score and so tries to update red team highscore;
oracle Blocks trasaction B because that row is now locked with a conflicting write
A inserts into the games table;
A commits;
B is unblocked, and completes the update, clobbering the 150 with a 125 and my invariant condition will be broken.
First question -- is this a correct understanding of READ_COMMITED?
My reading of SERIALIZABLE, however:
Oracle Database permits a serializable transaction to modify a row only if changes to the row made by other transactions were already committed when the serializable transaction began. The database generates an error when a serializable transaction tries to update or delete data changed by a different transaction that committed after the serializable transaction began.
Suggest that serializable won't do the right thing in the above scenario either, the only difference being that transaction B would get an error and I would have options to rollback or try again. This is doable, but seems unnecessarily difficult.
Second question -- is this a correct understanding of SERIALIZABLE?
... And if so, I am flummoxed. This seems like a simple, common thing to want to do. In code, I could accomplish this trivially by putting a mutex around the test-and-update of each team's high score.
Third and most important question: How do I get Oracle (or any SQL database, for that matter) to what I want here?
UPDATE: further reading suggests I probably need to do some explicit table locking, as in (https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9015.htm) -- but I'm not clear on exactly what I need. HALP!?
sql oracle relational-database concurrentmodification transaction-isolation
add a comment |
I've been reading about Oracle data consistency guarantees, and supported transaction isolation levels, (e.g. here: https://docs.oracle.com/database/121/CNCPT/consist.htm#CNCPT121) and I feel like I'm getting a lot of high-level information, but I'm not sure how it applies to my specific question.
I'm going to describe a simplified version of my use case, and I'm looking for convincing answers, preferably with references, as to how I need to structure my transaction to get the desired result. (Please don't get too hung up on syntax or data normalization or even data types in my question; it's a straw man -- so if you know what I mean, move on and focus on the concurrency problem.) :)
The Scenario (simplified):
Many users (tens of thousands) are playing an online game simultaneously. Players are all members of two teams, red or blue. Every time a player finishes a game, we want to log the user, their team affiliation, a timestamp, and the score. We also want to aggregate the highest score ever achieved by each team. Our data model looks like this:
// each game is logged in a table that looks kind of like this:
GAMES
time NUMBER,
userid NUMBER,
team NUMBER,
score NUMBER
// high scores are tracked here, assume initial 0-score was inserted at time 0
HIGH_SCORES
team NUMBER,
highscore NUMBER
So, for each score report I receive, I execute a transaction that looks like this
BEGIN
UPDATE HIGH_SCORES set highscore=:1 WHERE team=:2 and :1>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (:1,:2,:3,:4);
COMMIT
The invariant I wish to preserve is that, at any point in time, the high score for each team, as shown in the HIGH_SCORES table will be the highest score I would find if I were to scan the GAMES table and find highscore the hard way.
My understanding of the READ_COMMITED isolation level suggests this won't get me what I want:
Conflicting Writes in Read Committed Transactions
In a read committed transaction, a conflicting write occurs when the transaction attempts to change a row updated by an uncommitted concurrent transaction, sometimes called a blocking transaction. The read committed transaction waits for the blocking transaction to end and release its row lock.
The options are as follows:
If the blocking transaction rolls back, then the waiting transaction proceeds to change the previously locked row as if the other transaction never existed.
If the blocking transaction commits and releases its locks, then the waiting transaction proceeds with its intended update to the newly changed row.
It seems to me that if red team (team 1) has a high score of 100, and two players simultaneously submit better scores, a multithreaded server could have two database transactions going on that begin at the same time:
# Transaction A
UPDATE HIGHSCORES set highscore=150 where team=1 and 150>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (9999,100,1,150);
and
# Transaction B
UPDATE HIGHSCORES set highscore=125 where team=1 and 125>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (9999,101,1,125);
So (In READ_COMMITED mode,) you could get the following sequence: (c.f. Table 9-2 in the Oracle link referenced above)
A updates highscore for red team row; oracle locks this row
B still sees the 100 score and so tries to update red team highscore;
oracle Blocks trasaction B because that row is now locked with a conflicting write
A inserts into the games table;
A commits;
B is unblocked, and completes the update, clobbering the 150 with a 125 and my invariant condition will be broken.
First question -- is this a correct understanding of READ_COMMITED?
My reading of SERIALIZABLE, however:
Oracle Database permits a serializable transaction to modify a row only if changes to the row made by other transactions were already committed when the serializable transaction began. The database generates an error when a serializable transaction tries to update or delete data changed by a different transaction that committed after the serializable transaction began.
Suggest that serializable won't do the right thing in the above scenario either, the only difference being that transaction B would get an error and I would have options to rollback or try again. This is doable, but seems unnecessarily difficult.
Second question -- is this a correct understanding of SERIALIZABLE?
... And if so, I am flummoxed. This seems like a simple, common thing to want to do. In code, I could accomplish this trivially by putting a mutex around the test-and-update of each team's high score.
Third and most important question: How do I get Oracle (or any SQL database, for that matter) to what I want here?
UPDATE: further reading suggests I probably need to do some explicit table locking, as in (https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9015.htm) -- but I'm not clear on exactly what I need. HALP!?
sql oracle relational-database concurrentmodification transaction-isolation
add a comment |
I've been reading about Oracle data consistency guarantees, and supported transaction isolation levels, (e.g. here: https://docs.oracle.com/database/121/CNCPT/consist.htm#CNCPT121) and I feel like I'm getting a lot of high-level information, but I'm not sure how it applies to my specific question.
I'm going to describe a simplified version of my use case, and I'm looking for convincing answers, preferably with references, as to how I need to structure my transaction to get the desired result. (Please don't get too hung up on syntax or data normalization or even data types in my question; it's a straw man -- so if you know what I mean, move on and focus on the concurrency problem.) :)
The Scenario (simplified):
Many users (tens of thousands) are playing an online game simultaneously. Players are all members of two teams, red or blue. Every time a player finishes a game, we want to log the user, their team affiliation, a timestamp, and the score. We also want to aggregate the highest score ever achieved by each team. Our data model looks like this:
// each game is logged in a table that looks kind of like this:
GAMES
time NUMBER,
userid NUMBER,
team NUMBER,
score NUMBER
// high scores are tracked here, assume initial 0-score was inserted at time 0
HIGH_SCORES
team NUMBER,
highscore NUMBER
So, for each score report I receive, I execute a transaction that looks like this
BEGIN
UPDATE HIGH_SCORES set highscore=:1 WHERE team=:2 and :1>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (:1,:2,:3,:4);
COMMIT
The invariant I wish to preserve is that, at any point in time, the high score for each team, as shown in the HIGH_SCORES table will be the highest score I would find if I were to scan the GAMES table and find highscore the hard way.
My understanding of the READ_COMMITED isolation level suggests this won't get me what I want:
Conflicting Writes in Read Committed Transactions
In a read committed transaction, a conflicting write occurs when the transaction attempts to change a row updated by an uncommitted concurrent transaction, sometimes called a blocking transaction. The read committed transaction waits for the blocking transaction to end and release its row lock.
The options are as follows:
If the blocking transaction rolls back, then the waiting transaction proceeds to change the previously locked row as if the other transaction never existed.
If the blocking transaction commits and releases its locks, then the waiting transaction proceeds with its intended update to the newly changed row.
It seems to me that if red team (team 1) has a high score of 100, and two players simultaneously submit better scores, a multithreaded server could have two database transactions going on that begin at the same time:
# Transaction A
UPDATE HIGHSCORES set highscore=150 where team=1 and 150>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (9999,100,1,150);
and
# Transaction B
UPDATE HIGHSCORES set highscore=125 where team=1 and 125>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (9999,101,1,125);
So (In READ_COMMITED mode,) you could get the following sequence: (c.f. Table 9-2 in the Oracle link referenced above)
A updates highscore for red team row; oracle locks this row
B still sees the 100 score and so tries to update red team highscore;
oracle Blocks trasaction B because that row is now locked with a conflicting write
A inserts into the games table;
A commits;
B is unblocked, and completes the update, clobbering the 150 with a 125 and my invariant condition will be broken.
First question -- is this a correct understanding of READ_COMMITED?
My reading of SERIALIZABLE, however:
Oracle Database permits a serializable transaction to modify a row only if changes to the row made by other transactions were already committed when the serializable transaction began. The database generates an error when a serializable transaction tries to update or delete data changed by a different transaction that committed after the serializable transaction began.
Suggest that serializable won't do the right thing in the above scenario either, the only difference being that transaction B would get an error and I would have options to rollback or try again. This is doable, but seems unnecessarily difficult.
Second question -- is this a correct understanding of SERIALIZABLE?
... And if so, I am flummoxed. This seems like a simple, common thing to want to do. In code, I could accomplish this trivially by putting a mutex around the test-and-update of each team's high score.
Third and most important question: How do I get Oracle (or any SQL database, for that matter) to what I want here?
UPDATE: further reading suggests I probably need to do some explicit table locking, as in (https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9015.htm) -- but I'm not clear on exactly what I need. HALP!?
sql oracle relational-database concurrentmodification transaction-isolation
I've been reading about Oracle data consistency guarantees, and supported transaction isolation levels, (e.g. here: https://docs.oracle.com/database/121/CNCPT/consist.htm#CNCPT121) and I feel like I'm getting a lot of high-level information, but I'm not sure how it applies to my specific question.
I'm going to describe a simplified version of my use case, and I'm looking for convincing answers, preferably with references, as to how I need to structure my transaction to get the desired result. (Please don't get too hung up on syntax or data normalization or even data types in my question; it's a straw man -- so if you know what I mean, move on and focus on the concurrency problem.) :)
The Scenario (simplified):
Many users (tens of thousands) are playing an online game simultaneously. Players are all members of two teams, red or blue. Every time a player finishes a game, we want to log the user, their team affiliation, a timestamp, and the score. We also want to aggregate the highest score ever achieved by each team. Our data model looks like this:
// each game is logged in a table that looks kind of like this:
GAMES
time NUMBER,
userid NUMBER,
team NUMBER,
score NUMBER
// high scores are tracked here, assume initial 0-score was inserted at time 0
HIGH_SCORES
team NUMBER,
highscore NUMBER
So, for each score report I receive, I execute a transaction that looks like this
BEGIN
UPDATE HIGH_SCORES set highscore=:1 WHERE team=:2 and :1>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (:1,:2,:3,:4);
COMMIT
The invariant I wish to preserve is that, at any point in time, the high score for each team, as shown in the HIGH_SCORES table will be the highest score I would find if I were to scan the GAMES table and find highscore the hard way.
My understanding of the READ_COMMITED isolation level suggests this won't get me what I want:
Conflicting Writes in Read Committed Transactions
In a read committed transaction, a conflicting write occurs when the transaction attempts to change a row updated by an uncommitted concurrent transaction, sometimes called a blocking transaction. The read committed transaction waits for the blocking transaction to end and release its row lock.
The options are as follows:
If the blocking transaction rolls back, then the waiting transaction proceeds to change the previously locked row as if the other transaction never existed.
If the blocking transaction commits and releases its locks, then the waiting transaction proceeds with its intended update to the newly changed row.
It seems to me that if red team (team 1) has a high score of 100, and two players simultaneously submit better scores, a multithreaded server could have two database transactions going on that begin at the same time:
# Transaction A
UPDATE HIGHSCORES set highscore=150 where team=1 and 150>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (9999,100,1,150);
and
# Transaction B
UPDATE HIGHSCORES set highscore=125 where team=1 and 125>highscore;
INSERT into GAMES (time, userid, team, score) VALUES (9999,101,1,125);
So (In READ_COMMITED mode,) you could get the following sequence: (c.f. Table 9-2 in the Oracle link referenced above)
A updates highscore for red team row; oracle locks this row
B still sees the 100 score and so tries to update red team highscore;
oracle Blocks trasaction B because that row is now locked with a conflicting write
A inserts into the games table;
A commits;
B is unblocked, and completes the update, clobbering the 150 with a 125 and my invariant condition will be broken.
First question -- is this a correct understanding of READ_COMMITED?
My reading of SERIALIZABLE, however:
Oracle Database permits a serializable transaction to modify a row only if changes to the row made by other transactions were already committed when the serializable transaction began. The database generates an error when a serializable transaction tries to update or delete data changed by a different transaction that committed after the serializable transaction began.
Suggest that serializable won't do the right thing in the above scenario either, the only difference being that transaction B would get an error and I would have options to rollback or try again. This is doable, but seems unnecessarily difficult.
Second question -- is this a correct understanding of SERIALIZABLE?
... And if so, I am flummoxed. This seems like a simple, common thing to want to do. In code, I could accomplish this trivially by putting a mutex around the test-and-update of each team's high score.
Third and most important question: How do I get Oracle (or any SQL database, for that matter) to what I want here?
UPDATE: further reading suggests I probably need to do some explicit table locking, as in (https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9015.htm) -- but I'm not clear on exactly what I need. HALP!?
sql oracle relational-database concurrentmodification transaction-isolation
sql oracle relational-database concurrentmodification transaction-isolation
asked Mar 8 at 17:16
JVMATLJVMATL
1,549922
1,549922
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Wow, long question. The short answer is that READ_COMMITTED is all you need.
You will not get a lost-update because the UPDATE performed by transaction B will restart after transaction A commits. The UPDATE will be read-consistent as of the point in time it was restarted, not the point in time that is was submitted.
That is, in your example, transaction B will update 0 rows in HIGH_SCORES.
There is a good example of this in Chapter 9 of the Oracle Concepts guide, demonstrating how Oracle protects applications from lost-updates.
There is a good explanation of how and why Oracle will internally restart UPDATE statements for read-consistency by Tom Kyte, here: https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:11504247549852
add a comment |
is this a correct understanding of READ_COMMITED?
Not quite. Your scenario is not what is shown in table 9-2 in the documentation you linked to. Your scenario is essentially what is in table 9-4.
The difference is the 9-2 version (showing a lost update) doesn't check the value being updated - it doesn't filter on the existing salary, which is the column it's updating. The 9-4 version is updating a phone number but looking at the existing value for that column as part of the update, and the blocked update ends up not updating any rows because it re-reads the newly-changed value - which now doesn't match the filter.
Essentially the blocked update is re-run when the lock previous lock is removed, so it re-reads the newly committed data, and used that to decide whether the row now needs to be updated.
As that document also says:
Locks achieve the following important database requirements:
- Consistency
The data a session is viewing or changing must not be changed by other sessions until the user is finished.
- Integrity
The data and structures must reflect all changes made to them in the correct sequence.
Oracle Database provides data concurrency, consistency, and integrity among transactions through its locking mechanisms. Locking occurs automatically and requires no user action.
The last two sentences mean that you don't need to worry about it, and it's fairly easy to verify the behaviour by manually updating the same row in a table from two sessions.
And under automatic locks:
A DML lock, also called a data lock, guarantees the integrity of data accessed concurrently by multiple users. For example, a DML lock prevents two customers from buying the last copy of a book available from an online bookseller. DML locks prevent destructive interference of simultaneous conflicting DML or DDL operations.
In your case when it restarts the update that was blocked in your transaction B, it doesn't find a row for team 1 where highscore is less than 125. The data the statement executes against includes the committed updated from session A, even though that commit happened after B first identified and asked for the lock on the row which - at that point - did match its filter. So there is nothing for it to update, and the update from session A is not lost.
add a comment |
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55067993%2fconsistency-for-simultaneous-updates-in-oracle-when-the-where-clause-depends-on%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Wow, long question. The short answer is that READ_COMMITTED is all you need.
You will not get a lost-update because the UPDATE performed by transaction B will restart after transaction A commits. The UPDATE will be read-consistent as of the point in time it was restarted, not the point in time that is was submitted.
That is, in your example, transaction B will update 0 rows in HIGH_SCORES.
There is a good example of this in Chapter 9 of the Oracle Concepts guide, demonstrating how Oracle protects applications from lost-updates.
There is a good explanation of how and why Oracle will internally restart UPDATE statements for read-consistency by Tom Kyte, here: https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:11504247549852
add a comment |
Wow, long question. The short answer is that READ_COMMITTED is all you need.
You will not get a lost-update because the UPDATE performed by transaction B will restart after transaction A commits. The UPDATE will be read-consistent as of the point in time it was restarted, not the point in time that is was submitted.
That is, in your example, transaction B will update 0 rows in HIGH_SCORES.
There is a good example of this in Chapter 9 of the Oracle Concepts guide, demonstrating how Oracle protects applications from lost-updates.
There is a good explanation of how and why Oracle will internally restart UPDATE statements for read-consistency by Tom Kyte, here: https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:11504247549852
add a comment |
Wow, long question. The short answer is that READ_COMMITTED is all you need.
You will not get a lost-update because the UPDATE performed by transaction B will restart after transaction A commits. The UPDATE will be read-consistent as of the point in time it was restarted, not the point in time that is was submitted.
That is, in your example, transaction B will update 0 rows in HIGH_SCORES.
There is a good example of this in Chapter 9 of the Oracle Concepts guide, demonstrating how Oracle protects applications from lost-updates.
There is a good explanation of how and why Oracle will internally restart UPDATE statements for read-consistency by Tom Kyte, here: https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:11504247549852
Wow, long question. The short answer is that READ_COMMITTED is all you need.
You will not get a lost-update because the UPDATE performed by transaction B will restart after transaction A commits. The UPDATE will be read-consistent as of the point in time it was restarted, not the point in time that is was submitted.
That is, in your example, transaction B will update 0 rows in HIGH_SCORES.
There is a good example of this in Chapter 9 of the Oracle Concepts guide, demonstrating how Oracle protects applications from lost-updates.
There is a good explanation of how and why Oracle will internally restart UPDATE statements for read-consistency by Tom Kyte, here: https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:11504247549852
answered Mar 8 at 17:46
Matthew McPeakMatthew McPeak
10.3k11234
10.3k11234
add a comment |
add a comment |
is this a correct understanding of READ_COMMITED?
Not quite. Your scenario is not what is shown in table 9-2 in the documentation you linked to. Your scenario is essentially what is in table 9-4.
The difference is the 9-2 version (showing a lost update) doesn't check the value being updated - it doesn't filter on the existing salary, which is the column it's updating. The 9-4 version is updating a phone number but looking at the existing value for that column as part of the update, and the blocked update ends up not updating any rows because it re-reads the newly-changed value - which now doesn't match the filter.
Essentially the blocked update is re-run when the lock previous lock is removed, so it re-reads the newly committed data, and used that to decide whether the row now needs to be updated.
As that document also says:
Locks achieve the following important database requirements:
- Consistency
The data a session is viewing or changing must not be changed by other sessions until the user is finished.
- Integrity
The data and structures must reflect all changes made to them in the correct sequence.
Oracle Database provides data concurrency, consistency, and integrity among transactions through its locking mechanisms. Locking occurs automatically and requires no user action.
The last two sentences mean that you don't need to worry about it, and it's fairly easy to verify the behaviour by manually updating the same row in a table from two sessions.
And under automatic locks:
A DML lock, also called a data lock, guarantees the integrity of data accessed concurrently by multiple users. For example, a DML lock prevents two customers from buying the last copy of a book available from an online bookseller. DML locks prevent destructive interference of simultaneous conflicting DML or DDL operations.
In your case when it restarts the update that was blocked in your transaction B, it doesn't find a row for team 1 where highscore is less than 125. The data the statement executes against includes the committed updated from session A, even though that commit happened after B first identified and asked for the lock on the row which - at that point - did match its filter. So there is nothing for it to update, and the update from session A is not lost.
add a comment |
is this a correct understanding of READ_COMMITED?
Not quite. Your scenario is not what is shown in table 9-2 in the documentation you linked to. Your scenario is essentially what is in table 9-4.
The difference is the 9-2 version (showing a lost update) doesn't check the value being updated - it doesn't filter on the existing salary, which is the column it's updating. The 9-4 version is updating a phone number but looking at the existing value for that column as part of the update, and the blocked update ends up not updating any rows because it re-reads the newly-changed value - which now doesn't match the filter.
Essentially the blocked update is re-run when the lock previous lock is removed, so it re-reads the newly committed data, and used that to decide whether the row now needs to be updated.
As that document also says:
Locks achieve the following important database requirements:
- Consistency
The data a session is viewing or changing must not be changed by other sessions until the user is finished.
- Integrity
The data and structures must reflect all changes made to them in the correct sequence.
Oracle Database provides data concurrency, consistency, and integrity among transactions through its locking mechanisms. Locking occurs automatically and requires no user action.
The last two sentences mean that you don't need to worry about it, and it's fairly easy to verify the behaviour by manually updating the same row in a table from two sessions.
And under automatic locks:
A DML lock, also called a data lock, guarantees the integrity of data accessed concurrently by multiple users. For example, a DML lock prevents two customers from buying the last copy of a book available from an online bookseller. DML locks prevent destructive interference of simultaneous conflicting DML or DDL operations.
In your case when it restarts the update that was blocked in your transaction B, it doesn't find a row for team 1 where highscore is less than 125. The data the statement executes against includes the committed updated from session A, even though that commit happened after B first identified and asked for the lock on the row which - at that point - did match its filter. So there is nothing for it to update, and the update from session A is not lost.
add a comment |
is this a correct understanding of READ_COMMITED?
Not quite. Your scenario is not what is shown in table 9-2 in the documentation you linked to. Your scenario is essentially what is in table 9-4.
The difference is the 9-2 version (showing a lost update) doesn't check the value being updated - it doesn't filter on the existing salary, which is the column it's updating. The 9-4 version is updating a phone number but looking at the existing value for that column as part of the update, and the blocked update ends up not updating any rows because it re-reads the newly-changed value - which now doesn't match the filter.
Essentially the blocked update is re-run when the lock previous lock is removed, so it re-reads the newly committed data, and used that to decide whether the row now needs to be updated.
As that document also says:
Locks achieve the following important database requirements:
- Consistency
The data a session is viewing or changing must not be changed by other sessions until the user is finished.
- Integrity
The data and structures must reflect all changes made to them in the correct sequence.
Oracle Database provides data concurrency, consistency, and integrity among transactions through its locking mechanisms. Locking occurs automatically and requires no user action.
The last two sentences mean that you don't need to worry about it, and it's fairly easy to verify the behaviour by manually updating the same row in a table from two sessions.
And under automatic locks:
A DML lock, also called a data lock, guarantees the integrity of data accessed concurrently by multiple users. For example, a DML lock prevents two customers from buying the last copy of a book available from an online bookseller. DML locks prevent destructive interference of simultaneous conflicting DML or DDL operations.
In your case when it restarts the update that was blocked in your transaction B, it doesn't find a row for team 1 where highscore is less than 125. The data the statement executes against includes the committed updated from session A, even though that commit happened after B first identified and asked for the lock on the row which - at that point - did match its filter. So there is nothing for it to update, and the update from session A is not lost.
is this a correct understanding of READ_COMMITED?
Not quite. Your scenario is not what is shown in table 9-2 in the documentation you linked to. Your scenario is essentially what is in table 9-4.
The difference is the 9-2 version (showing a lost update) doesn't check the value being updated - it doesn't filter on the existing salary, which is the column it's updating. The 9-4 version is updating a phone number but looking at the existing value for that column as part of the update, and the blocked update ends up not updating any rows because it re-reads the newly-changed value - which now doesn't match the filter.
Essentially the blocked update is re-run when the lock previous lock is removed, so it re-reads the newly committed data, and used that to decide whether the row now needs to be updated.
As that document also says:
Locks achieve the following important database requirements:
- Consistency
The data a session is viewing or changing must not be changed by other sessions until the user is finished.
- Integrity
The data and structures must reflect all changes made to them in the correct sequence.
Oracle Database provides data concurrency, consistency, and integrity among transactions through its locking mechanisms. Locking occurs automatically and requires no user action.
The last two sentences mean that you don't need to worry about it, and it's fairly easy to verify the behaviour by manually updating the same row in a table from two sessions.
And under automatic locks:
A DML lock, also called a data lock, guarantees the integrity of data accessed concurrently by multiple users. For example, a DML lock prevents two customers from buying the last copy of a book available from an online bookseller. DML locks prevent destructive interference of simultaneous conflicting DML or DDL operations.
In your case when it restarts the update that was blocked in your transaction B, it doesn't find a row for team 1 where highscore is less than 125. The data the statement executes against includes the committed updated from session A, even though that commit happened after B first identified and asked for the lock on the row which - at that point - did match its filter. So there is nothing for it to update, and the update from session A is not lost.
edited Mar 8 at 20:02
answered Mar 8 at 17:49
Alex PooleAlex Poole
134k6108183
134k6108183
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55067993%2fconsistency-for-simultaneous-updates-in-oracle-when-the-where-clause-depends-on%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
