【问题标题】:How to exclusively lock Oracle DB Table using C#?如何使用 C# 独占锁定 Oracle 数据库表?
【发布时间】:2017-10-27 08:35:08
【问题描述】:

实际上我想在一个表上应用锁,这样其他进程就不能执行 DML(插入/更新/删除但可以执行选择)或在“进程执行”时锁定该表。

LOCK TABLE table-name IN EXCLUSIVE MODE

我应该如何用 C# 编写?

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

如何解除锁定?我猜是提交或回滚。

有什么建议吗?

【问题讨论】:

    标签: c# oracle


    【解决方案1】:

    锁将在提交或回滚时释放

    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();
    

    【讨论】:

    • 但我刚刚在 msdn 上发现:ExecuteNonQuery 不使用游标,因此不会在数据库上加锁。如果您发出需要锁定的命令,请不要使用 ExecuteNonQuery。相反,使用 ExecuteReader。那怎么用??此外,在我的情况下,executenonquery 返回 0。但是它写在 msdn 上:对于 UPDATE、INSERT 和 DELETE 语句,返回值是受命令影响的行数。对于所有其他 DML 语句,返回值为 -1
    【解决方案2】:

    为什么需要锁定表? 使用事务范围对象指定隔离级别就足够了吗? 例如

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

    请检查您的要求。

    【讨论】:

    • 是的,隔离是一个不错的选择……但现在我遇到了另一个问题。在事务范围内我收到错误:尝试加载格式不正确的程序。 (来自 HRESULT 的异常:0x8007000B)。它缺少我下载的 oramts.dll。我用谷歌搜索了这个错误,发现它是因为 dll 文件的 BIT。我的 Oracle 客户端是 64 位的,因此它可能期望 oramts.dll 是 64 位的。我从哪里可以得到这个?
    • 在我看来你可以通过这个链接得到帮助support.microsoft.com/kb/843044
    • @knagaev 链接死了,bayb,链接死了……(低俗小说参考……没关系)
    • @Noctis 你弄坏了它 :) 你有一些 necroposting,嗯?
    • @knagaev 才 2.5 年……这不是 necroposting……它仍然很温暖……在这里,触摸它……通常的伙伴。有问题,谷歌,所以,点击链接,找到一些死的东西,通过提高认识来帮助社区...... :)
    【解决方案3】:

    通过利用另一种策略可以解决此问题。都没有解决:

    1. EXCLUSIVE LOCKING(因为我意识到如果在我的进程正在进行时有另一个事务更新了我的表,那么由于锁定而无法更新表,但是一旦我的进程完成,意味着锁现在被释放了,如果另一个事务仍然被搁置,那么另一个事务将立即更新我的表。这对我来说不会产生任何结果。)也不能通过以下方式解决它:

    2. IsolationLevel.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();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-05
      • 2023-01-10
      • 1970-01-01
      • 2015-10-05
      相关资源
      最近更新 更多