2010-03-05 57 views
1

我有一个表,其中包含最大值,需要由多个程序获取和设置。如何获取旧值并在C#中更新新内容时,如何锁定表格一段时间?换句话说:是否可以使用ADO.NET锁定Oracle 10g数据库表?

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!! 
} 
+6

广东话”你用Oracle序列呢?它会处理同步你。 – 2010-03-05 11:54:14

+0

@Peter郎。完美。一个序列也许马蒂可以解释他为什么不这样做 – Guru 2010-03-05 11:56:53

+0

@马蒂 - 彼得的建议是健全的 - 看看http://www.techonthenet.com/oracle/sequences.php – RichardOD 2010-03-05 11:57:22

回答

0

有一个LOCK TABLE命令

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

注:直到结束交易不能重新锁定。所以如果你锁定桌子,你不能解锁它。

+0

说什么?因为你可以从我的问题看到我知道oracle有锁定命令...它是在sql变量int代码示例。你是什​​么意思我不能重置锁?哪些交易?我只是在共享模式下再次锁定它。 – 2010-03-05 12:01:10

+0

不,如果您将其锁定在共享模式下,则该交易的其余部分将使用排他锁。你需要在这里交易。没有交易,锁定和事务隔离不起作用。 – 2010-03-05 12:28:35

2

Oracle可以自己处理locking。尝试尽可能使用数据库功能。

Sequence是甲骨文的首选方式,因为上面的注释会告诉你。

+1

如果您需要第一次创建行,您只是无法锁定它。你不能锁定那里不存在的东西。然后你需要桌子锁。 – 2010-03-05 12:25:30

0

为了在需要它的语句之后保持锁定,您需要一个事务。

1

听起来像是你应该使用Oracle Sequence代替 - 在我的评论:)

每当调用NEXTVAL将返回唯一的数字已经提到。


如果由于某种原因你不能”用一个序列,只要在该行执行UPDATE。 Oracle将锁定该行,直到您结束交易(COMMITROLLBACK),并且所有其他更新将一直等到锁被释放。


编辑

如果交易不是在ADO支持,你也可以使用它放入一个Oracle过程的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,锁定被释放,而您自己的交易不会受到影响。

+0

+1。这绝对是最好的方法,它提供了适合于序列提供的独特ID。 – RichardOD 2010-03-05 12:07:41

+0

对不起。我出于各种原因不能使用它:1.数据库和表是现有的,我无法改变它。 2.我可能需要一个变量范围或表中的值。即当我需要46(值得注意的)值时,我读取值65300并写入65345。序列的间隔是固定的。 – 2010-03-05 12:15:01

+0

在DAO.NET命令中,“只对该行执行UPDATE”意味着什么,不一定是事务的一部分(我认为)。所以你的意思是我创建了一个事务,然后选择命令,并将该命令作为事务处理,然后执行它,然后执行更新并执行并提交。并且oracle在开始选择时锁定表并在执行提交时将其解锁。 – 2010-03-05 12:20:57

-1

您可以尝试其他方法。首先在表上启用表格锁定。说我的桌子是T。然后

SQL> alter table t enable table lock 
2 /

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

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

因此,任何其他选择命令在其他会话中的其他位置不会返回并等待锁释放。请记住,您需要执行COMMIT才能解锁。

+0

行级锁定是默认功能,不需要使用“alter table ... enable table lock”。 – codenheim 2010-03-15 22:38:19

+0

没错。该查询在那里是为了防止表锁被禁用。 – Guru 2010-03-16 08:00:11

2

对指定的数据库使用提供程序通常是一种很好的做法。甲骨文在他的网站上有一个Microsoft.Net专用提供商,我会推荐使用它。请注意,所有专用提供程序都实现相同的基本类别,因此保留了某种抽象级别。其次,U肯定需要交易。我建议通过调用存储过程(通过executeNonQuery()或executeScalar()方法来实现 - 取决于结果U需要。

如果您不能使用存储过程(U无法创建它们)然后,您必须使用由供应商提供transations。无论奥莱提供商,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(); 
    } 
+0

谢谢。我稍后再试。你是第一个真正想回答我的问题的人! – 2010-03-23 08:17:45

相关问题