2010-03-05 266 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

相關問題