是否可以使用 ADO.NET 锁定 oracle 10g 数据库表?

发布于 2024-08-23 17:45:18 字数 480 浏览 5 评论 0原文

我有一个表,其中包含需要由多个程序获取和设置的最大值。在 C# 中,当获取旧值并更新新值时,如何锁定表一段时间?换句话说:

string sql = "lock table MaxValueTable in exclusive mode";  
using (DbCommand cmd = cnctn.CreateCommand())
{
    cmd.CommandText = sql;
    // execute command somehow!!
}

maxValue = GetMaxValue();
SetMaxValue(maxValue + X);

sql = "lock table MaxValueTable in share mode";  
using (DbCommand cmd = cnctn.CreateCommand())
{
    cmd.CommandText = sql;
    // execute command somehow!!
}

I have a table that contains a maximum value that needs to be get and set by multiple programs. How can I lock the table for a while when old value is got and new is updated in C#? In other words:

string sql = "lock table MaxValueTable in exclusive mode";  
using (DbCommand cmd = cnctn.CreateCommand())
{
    cmd.CommandText = sql;
    // execute command somehow!!
}

maxValue = GetMaxValue();
SetMaxValue(maxValue + X);

sql = "lock table MaxValueTable in share mode";  
using (DbCommand cmd = cnctn.CreateCommand())
{
    cmd.CommandText = sql;
    // execute command somehow!!
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

献世佛 2024-08-30 17:45:19

使用指定数据库的提供程序通常是一个好习惯。 Oracle 在其网站上有专门的 Microsoft.Net 提供程序,我建议使用它。请注意,所有专用提供程序都实现相同的基类,因此保留了一定的抽象级别。其次,你肯定需要一笔交易。我建议通过调用存储过程(通过executeNonQuery()或executeScalar()方法来做到这一点 - 取决于您需要的结果。

如果您不能使用存储过程(您无法创建它们)那么您必须使用提供商提供的交易 Ole 提供商和 ORacle 提供商都提供交易。

using (Transaction t = cnctn.BeginTransation())


`//set some options like timeout, use serialization level like //Serializable in .Net TransactionScope


   {
        string sql = "lock table MaxValueTable in exclusive mode";
        using (DbCommand cmd = cnctn.CreateCommand())
        { 
           cmd.CommandText = sql;
           cmd.ExecuteNonQuery();
          // execute command somehow!! 
        } 
       maxValue = GetMaxValue();
       SetMaxValue(maxValue + X);
       //I presume U need to update the value in the table so some Update would be nice
       sql = "lock table MaxValueTable in share mode";
       using (DbCommand cmd = cnctn.CreateCommand())
       { 
           cmd.CommandText = sql;
           cmd.ExecuteNonQuery();
           // execute command somehow!! 
       }
       cnctn.Commit();
  }
  catch(SQLException e)
  {
     //log whatever, gracefully handle things
     t.Rollback();
     //throw;?
  }
  finally
  {
        cntn.close();
  }

It's generally a good practice to use providers for a specified database. Oracle has a dedicated provider for Microsoft.Net on his site, I would recommend using it. Note that all dedicated providers implement the same base classess so certain level of abstraction is kept. Secondly U definately need a transaction. I'd recommend doing that by invoking a stored procedure (either by executeNonQuery() or executeScalar() methods - depending on the result U need.

If You can't use stored procedures (U can't create them) then You have to use transations offered by the provider. Both Ole provider and ORacle provider offer transaction

using (Transaction t = cnctn.BeginTransation())


`//set some options like timeout, use serialization level like //Serializable in .Net TransactionScope


   {
        string sql = "lock table MaxValueTable in exclusive mode";
        using (DbCommand cmd = cnctn.CreateCommand())
        { 
           cmd.CommandText = sql;
           cmd.ExecuteNonQuery();
          // execute command somehow!! 
        } 
       maxValue = GetMaxValue();
       SetMaxValue(maxValue + X);
       //I presume U need to update the value in the table so some Update would be nice
       sql = "lock table MaxValueTable in share mode";
       using (DbCommand cmd = cnctn.CreateCommand())
       { 
           cmd.CommandText = sql;
           cmd.ExecuteNonQuery();
           // execute command somehow!! 
       }
       cnctn.Commit();
  }
  catch(SQLException e)
  {
     //log whatever, gracefully handle things
     t.Rollback();
     //throw;?
  }
  finally
  {
        cntn.close();
  }
俏︾媚 2024-08-30 17:45:19

听起来你应该使用 Oracle Sequence - 正如我的评论中已经提到的: )

每当调用 NEXTVAL 时,它都会返回唯一的数字。


如果由于某种原因您无法使用序列,只需对该行执行 UPDATE 即可。 Oracle 将锁定该行,直到您结束事务(COMMITROLLBACK),并且所有其他更新将等待直到锁定被释放。


编辑

如果 ADO 不支持事务,您还可以使用 AUTONOMOUS_TRANSACTION

CREATE OR REPLACE PROCEDURE allocate_sequence_numbers(
  in_size IN max_value_table.val%TYPE,
  out_next_sequence_number OUT max_value_table.val%TYPE
)
AS
  PRAGMA AUTONOMOUS_TRANSACTION;
  next_sequence_number max_value_table.val%TYPE;
BEGIN
  UPDATE max_value_table
  SET val = val + in_size
  RETURNING val - in_size
  INTO out_next_sequence_number;
  COMMIT;
END allocate_sequence_numbers;

它将更新您的表以“分配”指定数量的值,并返回您分配的序列的第一个数字。下一个调用它的应用程序将收到下一个序列号。

UPDATE 会导致该行上的锁,因此其他调用必须等待该锁被释放。通过在AUTONOMOUS_TRANSACTION内部使用COMMIT,锁被释放,而你自己的事务不会受到影响。

Sounds like you should be using an Oracle Sequence instead - as already mentioned in my comment :)

It will return unique numbers whenever calling NEXTVAL.


If for some reason you cant' use a sequence, just perform an UPDATE on that row. Oracle will lock that row until you end your transaction (COMMIT or ROLLBACK) and all other updates will wait until the lock is released.


EDIT:

If transactions are not supported in ADO, you could also put that into an Oracle Procedure using an AUTONOMOUS_TRANSACTION:

CREATE OR REPLACE PROCEDURE allocate_sequence_numbers(
  in_size IN max_value_table.val%TYPE,
  out_next_sequence_number OUT max_value_table.val%TYPE
)
AS
  PRAGMA AUTONOMOUS_TRANSACTION;
  next_sequence_number max_value_table.val%TYPE;
BEGIN
  UPDATE max_value_table
  SET val = val + in_size
  RETURNING val - in_size
  INTO out_next_sequence_number;
  COMMIT;
END allocate_sequence_numbers;

It will update your table to "allocate" the specified number of values, and return the first number of the sequence you allocated. The next application that calls it will receive the next sequence number.

The UPDATE causes a lock on that row, so other calls have to wait for that lock to be released. By using COMMIT inside the AUTONOMOUS_TRANSACTION, the lock is released, while your own transaction will not be affected.

花心好男孩 2024-08-30 17:45:19

有一个锁表命令

LOCK TABLE [schema.] table IN lockmode EXCLUSIVE [NOWAIT]

注意:在结束事务之前你不能重置锁。因此,如果您锁定了表,则无法将其解锁。

There is a lock table command

LOCK TABLE [schema.] table IN lockmode EXCLUSIVE [NOWAIT]

Note: you can't reset a lock until you end the transaction. So if you locked the table, you can't unlock it.

只涨不跌 2024-08-30 17:45:19

要在获取锁的语句之后保留锁,您需要一个事务。

To keep the lock after the statement that takes it you need a transaction.

蓝海 2024-08-30 17:45:19

您可以尝试另一种方法。首先在表上启用表锁定。假设我的桌子是T。然后

SQL> alter table t enable table lock   
2    /

现在,您可以选择,任何其他选择都会等待,因为您有锁。

SQL> select *
  2  from t
  3  for update
  4  /

因此,另一个会话中其他位置的任何选择命令都不会返回并等待锁被释放。请记住,您需要执行COMMIT 来释放锁。

You can try another method. First enable table locking on the table. Say my table is T. Then

SQL> alter table t enable table lock   
2    /

Now, you can select, and any other select will wait, because you have a lock.

SQL> select *
  2  from t
  3  for update
  4  /

So, any select command else where in another session will not return and wait for the lock to be released. Remember, you need to do COMMIT to release the lock.

一影成城 2024-08-30 17:45:18

Oracle 可以自行处理锁定。尽可能尝试使用数据库功能。

序列是首选方式在 Oracle 中,上面的评论会告诉你。

Oracle can handle locking itself. Try to use Database features as far as possible.

Sequence is the preferred way in Oracle as comments above will tell you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文