0

我想知道以下行动方案是否可行:

我正在实现一个简单的数据输入应用程序。每个可编辑记录都驻留在一个表中。用户必须同时编辑多条记录(以减少数据输入时间)。我目前尝试做的是在记录中实现某种锁定机制。

我想到的第一件事是执行 (ExecuteNonQuery) UPDATE some_table SET status = 'locked' WHERE rownum = 1 RETURNING id INTO :locked_id 与输出参数,给我锁定记录的 ID。我可以根据这个 ID 执行另一个 SELECT 语句来读取我想要的任何其他信息。

虽然上述方法似乎适用于单个锁定记录,但我真的不知道如何为多个返回的行执行此操作。- 如果在上面的示例中,WHERE 子句是“rownum < 4”而不是“rownum = 1”怎么办?

我的 OracleParameter 应该是什么样的?当我像这样指定我的返回 oracle 参数时(适用于单行),

OracleParameter p = cmd.Parameters.Add("ID", OracleDbType.Int32, 10, 0, ParameterDirection.Output);

给出了 ORA-24369。我尝试使用 ArrayBindCount 和数组作为参数的 .Value 属性,但无济于事。

另外,您是否发现整个特定的锁定方式存在根本性的问题?

谢谢你

编辑:一些澄清 - 1. 有一个名为 user_name 的列,它可以保存例如登录用户的名称 - 我将它与锁定更新一起更新 2. 还有另一列我称之为locked_timestamp,它保存时间记录被锁定。可能会有一个后台进程在夜间运行并将锁定的记录重置回“解锁” - 鉴于这种情况不会经常发生,并且由于崩溃等原因保持“锁定”的记录比例很小与已编辑记录的数量相比 3. 并发更新应该由 Oracle 自动处理,是的,我在每次 UPDATE 期间都使用事务 - 所以一条记录同时被两个用户锁定的可能性很小 - 或者就是这样我听说(会试试这个,

4

2 回答 2

2

最后,经过数小时的搜索和代码操作,我得出了以下结论(除了头痛):

我得到了我想要的使用组合来自

  1. 这里有一个提示,它建议将 UPDATE..RETURNING 语句包装到一个匿名 PL/SQL 块中(以 BEGIN 开头,以 END 结尾;) - 这没有解释,我仍然不知道为什么行为不同
  2. Oracle 文档中关于 OracleCommand 的代码片段,特别是关于使用 BULK COLLECT INTO 绑定 PL/SQL 关联数组的部分(无法让简单的数组绑定工作..):

try
{
    conn.Open();
    transaction = conn.BeginTransaction();

    cmd = new OracleCommand();
    cmd.Connection = GetConnection();

    cmd.CommandText =
        "BEGIN UPDATE some_table " +
        "SET status = 'locked', " +
        "    locked_tstamp = SYSDATE, " +
        "    user_name = '" + user + "' " +
        "WHERE rownum <= 4 " +
        "RETURNING id BULK COLLECT INTO :id; END;";

    cmd.CommandType = CommandType.Text;

    cmd.BindByName = true;
    cmd.ArrayBindCount = 4;

    p = new OracleParameter();
    p.ParameterName = "id";
    p.Direction = ParameterDirection.Output;
    p.OracleDbType = OracleDbType.Int64;
    p.Size = 4;
    p.ArrayBindSize = new int[] { 10, 10, 10, 10 };
    p.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
    cmd.Parameters.Add(p);

    int nRowsAffected = cmd.ExecuteNonQuery();

    // nRowsAffected is always -1 here
    // we can check the number of "locked" rows only by counting elements in p.Value (which is returned as OracleDecimal[] here)
    // note that the code also works if less than 4 rows are updated, with the exception of 0 rows
    // in which case an exception is thrown - see below
    ...
}
catch (Exception ex)
{
    if (ex is OracleException && !String.IsNullOrEmpty(ex.Message) && ex.Message.Contains("ORA-22054")) // precision underflow (wth)..
    {
        Logger.Log.Info("0 rows fetched");
        transaction.Rollback();
    }
    else
    {
        Logger.Log.Error("Something went wrong during Get : " + ex.Message);
        ret = null;
        transaction.Rollback();
    }
}
finally
{
    // do disposals here
}
...

于 2012-04-18T15:00:08.783 回答
1

关于此记录锁定方案,需要考虑以下几点:

  1. 你怎么知道谁的记录被锁定了?我怀疑在某些时候你会想知道。
  2. 如果会话崩溃,记录如何解锁?他们肯定不会一直锁定到时间结束吗?!?
  3. 如何处理同时锁定尝试?假设我启动了一个事务来锁定记录#12345。我的应用程序看到该状态是“解锁”(或 NULL,或其他),并立即执行 UPDATE 和 COMMIT 以“锁定”记录。与此同时,隔壁立方体中的 Susie 也在做同样的事情——读取数据库,看看它是否被解锁,然后执行同样的 UPDATE 和 COMMIT。现在好 - 1) 记录的状态是什么,2) 谁真的把它锁定了,3) 谁的后续更改将被覆盖 - 我告诉你,最好是 Susie 或者我来了' 在那里大声谈论这个!

只是有几点需要思考。

分享和享受。

于 2012-04-12T17:00:32.523 回答