如何使用c#独占锁Oracle DB表

本文关键字:Oracle DB 何使用 | 更新日期: 2023-09-27 18:04:06

实际上我想在表上应用锁,这样在'进程执行'时,没有其他进程可以执行DML(插入/更新/删除,但可以执行Select)或锁表。

LOCK TABLE table-name IN EXCLUSIVE MODE

我应该如何写在c# ?

//……进程执行.......

如何释放锁?我想要么提交,要么回滚。

有什么建议吗?

如何使用c#独占锁Oracle DB表

锁将在提交或回滚时被释放

OracleConnection conn= new OracleConnection("Data Source=datasrc;User=USER;Password=passwd");
conn.Open();
OracleTransaction tr = conn.BeginTransaction();
OracleCommand cmd = new OracleCommand("LOCK TABLE TABLE_NAME IN EXCLUSIVE MODE",conn,tr);
cmd.ExecuteNonQuery();
Console.ReadLine();
tr.Commit();
conn.Close();

为什么需要锁表?也许使用事务作用域对象指定隔离级别就足够了?例如

TransactionOptions TransOpt = New TransactionOptions();
TransOpt.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, TransOptions))
{
...
}

请检查您的要求

可以利用另一种策略来解决这个问题。

  1. EXCLUSIVE LOCKING(因为我意识到如果有另一个事务更新了我的表,而我的进程正在进行中,由于锁无法更新表,但一旦我的进程完成,意味着锁现在释放,如果另一个事务仍然处于暂停状态,那么另一个事务将立即更新我的表。这对我来说不会有结果。)

  2. IsolationLevel。Serializable(由于分布式事务不支持Serializable事务隔离级别)

因此,在我的表中的每个条目上,我确定是否有任何事务(无论是分布式的还是本地的)阻塞了我的表。如果存在,我就会识别该会话并强制终止该会话。这非常适合我的场景:

Database db = DataRepository.GetDatabase();
int result, session_id = 0;
string kill_session, serial = null;
string chk_lock = "SELECT l.session_id,v.serial# ,"
                +"object_name FROM dba_objects o, gv$locked_object l, "
                +"v$session v WHERE o.object_id = l.object_id and "
                +"l.SESSION_ID=v.sid";
DbDataReader rdr_blkAccount;
try{
    //MY PROCESS RUNS HERE...
}
catch(Exception excep)
{
    //...
}
finally
{
    rdr_blkAccount = db.ExecuteReader(chk_lock);
    while (rdr_blkAccount.Read())
    {
        if (rdr_blkAccount[2].ToString().ToUpper() == "ACCOUNT")
        {
            session_id = Convert.ToInt32(rdr_blkAccount[0]);
            serial = session_id.ToString() + ','
                   + Convert.ToInt32(rdr_blkAccount[1]).ToString();
            kill_session = "alter system kill session '" + serial + "'";
            result = db.ExecuteNonQuery(kill_session);
            logger.Log( LogLevel.Warning 
                      , string.Format("Session_id '{0}' has been forcefully killed"
                                     , serial));
        }
    }
    rdr_blkAccount.Close();
}