简体   繁体   English

在Oracle中读取COMMITTED数据库隔离级别

[英]READ COMMITTED database isolation level in oracle

I'm working on a web app connected to oracle. 我正在开发一个连接到oracle的网络应用程序。 We have a table in oracle with a column "activated". 我们在oracle中有一个表“激活”列。 Only one row can have this column set to 1 at any one time. 任何时候只有一行可以将此列设置为1。 To enforce this, we have been using SERIALIZED isolation level in Java, however we are running into the "cannot serialize transaction" error, and cannot work out why. 为了强制执行此操作,我们一直在Java中使用SERIALIZED隔离级别,但是我们遇到了“无法序列化事务”错误,并且无法解决原因。

We were wondering if an isolation level of READ COMMITTED would do the job. 我们想知道READ COMMITTED的隔离级别是否可以完成这项工作。 So my question is this: 所以我的问题是:

If we have a transaction which involves the following SQL: 如果我们有一个涉及以下SQL的事务:

SELECT *
FROM MODEL;

UPDATE MODEL
SET ACTIVATED = 0;

UPDATE MODEL
SET ACTIVATED = 1
WHERE RISK_MODEL_ID = ?;

COMMIT;

Given that it is possible for more than one of these transactions to be executing at the same time, would it be possible for more than one MODEL row to have the activated flag set to 1 ? 假设这些事务中有多个事务可能同时执行,那么多个MODEL行是否可以将激活标志设置为1?

Any help would be appreciated. 任何帮助,将不胜感激。

your solution should work: your first update will lock the whole table. 您的解决方案应该工作:您的第一次更新将锁定整个表。 If another transaction is not finished, the update will wait. 如果另一个事务未完成,则更新将等待。 Your second update will guarantee that only one row will have the value 1 because you are locking the table (it doesn't prevent INSERT statements however). 您的第二次更新将保证只有一行的值为1,因为您正在锁定表(但它不会阻止INSERT语句)。

You should also make sure that the row with the RISK_MODEL_ID exists (or you will have zero row with the value '1' at the end of your transaction). 您还应该确保具有RISK_MODEL_ID的行存在(或者您将在事务结束时使用值为'1'的行为零)。

To prevent concurrent INSERT statements, you would LOCK the table (in EXCLUSIVE MODE). 要防止并发INSERT语句,您可以锁定表(在EXCLUSIVE MODE中)。

You could consider using a unique, function based index to let Oracle handle the constraint of only having a one row with activated flag set to 1. 您可以考虑使用一个基于函数的唯一索引来让Oracle处理只有一行激活标志设置为1的约束。

CREATE UNIQUE INDEX MODEL_IX ON MODEL ( DECODE(ACTIVATED, 1, 1, NULL));

This would stop more than one row having the flag set to 1, but does not mean that there is always one row with the flag set to 1. 这将停止将标志设置为1的多个行,但这并不意味着总是有一行将标志设置为1。

If what you want is to ensure that only one transaction can run at a time then you can use the FOR UPDATE syntax. 如果您想要确保一次只能运行一个事务,那么您可以使用FOR UPDATE语法。 As you have a single row which needs locking this is a very efficient approach. 由于您有一行需要锁定,这是一种非常有效的方法。

declare
    cursor c is 
        select activated
        from model
        where activated = 1
        for update of activated;
    r c%rowtype;
begin
    open c;
    --  this statement will fail if another transaction is running
    fetch c in r;
    ....
    update model
    set activated = 0
    where current of c;

    update model
    set activated = 1
    where risk_model_id = ?;

    close c;

    commit;
end;
/

The commit frees the lock. commit释放锁。

The default behaviour is to wait until the row is freed. 默认行为是等待释放行。 Otherwise we can specify NOWAIT , in which case any other session attempting to update the current active row will fail immediately, or we can add a WAIT option with a polling time. 否则我们可以指定NOWAIT ,在这种情况下,任何其他尝试更新当前活动行的会话都将立即失败,或者我们可以添加带轮询时间的WAIT选项。 NOWAIT is the option to choose to absolutely avoid the risk of hanging, and it also gives us the chance to inform the user that someone else is updating the table, which they might want to know. NOWAIT是选择绝对避免挂起风险的选项,它还使我们有机会通知用户其他人正在更新他们可能想知道的表。

This approach is much more scalable than updating all the rows in the table. 此方法比更新表中的所有行更具可伸缩性。 Use a function-based index as WW showed to enforce the rule that only one row can have ACTIVATED=1. 使用WW显示的基于函数的索引来强制执行只有一行可以具有ACTIVATED = 1的规则。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何提高代码以在Oracle的READ COMMITTED隔离级别中安全处理? - How to improve code to safely process in READ COMMITTED isolation level in Oracle? 读取并提交了具有无锁和事务隔离级别的SQL事务 - SQL Transactions with nolocks and TRANSACTION ISOLATION LEVEL READ COMMITTED SELECT语句 - 具有SET TRANSACTION ISOLATION LEVEL READ NOUOCK的NOLOCK - SELECT Statement - NOLOCK with SET TRANSACTION ISOLATION LEVEL READ COMMITTED 我们应该使用读提交隔离级别吗? - should we use read-committed isolation level? 在READ COMMITTED隔离级别的CTE子句中可能有不同的结果吗? - Is it possible to have different results in CTE clauses in READ COMMITTED isolation level? 读取提交的快照隔离和事务 - Read Committed Snapshot Isolation and Transactions 为什么 SQL 服务器在默认隔离级别为 READ COMMITTED 时会读取未提交的数据? - Why does SQL Server read uncommitted data when the default isolation level is READ COMMITTED? 是否可以在数据库级别设置无锁或“事务隔离级别未提交读”? - Is it possible to set no lock or TRANSACTION ISOLATION LEVEL READ UNCOMMITTED at database level? SELECT可以使用Read Committed Isolation Level在一个事务中获得不同的结果吗? - Can SELECT get different results within one transaction using Read Committed Isolation Level? SQL事务隔离级别可序列化与在开发与生产中提交的读取 - SQL Transaction Isolation Level Serializable vs Read Committed in Dev vs Production
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM