1

我有一个数据库表,用于记录其他表中发生的更改。我的日志表的表结构如下。

    Log_Table(id, table_name, operation, flag)
    values   (1,  Customer_Table, 1,       1);
    values   (2,  Customer_Table, 2,       1);
    values   (3,  Customer_Table, 1,       1);
    values   (4,  Customer_Table, 2,       1);
    values   (5,  Customer_Table, 1,       1);

我通过执行以下操作针对网页上的按钮更新此表:

/* first */
public List<Long> select_Changes()
{
    select id from Log_Table where flag =1;
}

/* (wait for user input) */

/* second */
public void update_table(List<Long> ids)
{
    update Log_Table set flag =0 where id in( ids)
}

问题是在第一次和第二次操作之间由用户来执行操作。同时另一个用户同时做同样的操作。我不希望第二个用户选择第一个用户已经选择的行;也就是说,当第二个用户运行第一步时(假设自第一个用户运行后又添加了两行),结果应该是:

    values(6,Customer,2,1);
    values(7,Customer,1,1);

请建议我应该怎么做?选择行后,我需要锁定行以进行任何类型的操作。我尝试了 select for update 子句,但没有解决问题。它在一个网络应用程序中。

4

2 回答 2

1

在等待用户输入时保持数据库事务打开几乎不是一个好主意。如果用户在交易未决时去吃午饭,或者他们的网络连接中断并且几天没有恢复怎么办?

此外,您没有说您使用的是什么数据库产品。根据产品、它的配置和事务隔离级别,并发尝试的结果是什么事务是未决的,所以如果你想要可移植的行为,你不能依赖于行为SELECT FOR UPDATE甚至更标准化的特性。

我的建议是在行中提供一种方法来识别等待用户确认的待处理行。您可以对列使用三种状态flag,以表示类似availablependingtaken; 但是,您可能希望有某种方法来识别呈现给用户但用户从未单击“确定”或“取消”(或任何选项)的行。如果为此目的添加时间戳列,则可以为该列保留两种状态,并在第一步flag使用类似这样的内容(假设您使用的是支持该子句的数据库):RETURNING

public List<Long> select_Changes()
{
    UPDATE Log_Table
      SET when_presented = CURRENT_TIMESTAMP
      WHERE flag = 1
        AND when_presented = NULL
      RETURNING id, when_presented;
}

第二步将改为:

public void update_table(List<Long> ids)
{
    UPDATE Log_Table
      SET flag = 0
      WHERE id IN (ids)
        AND when_presented = time_claimed;
}

第二步不一定需要更改,但是通过上述更改,您可以使用另一个RETURNING子句来确认该用户实际声明了哪些值,如果维护过程重新设置到明显放弃的行集上id,则关闭竞争条件,否则会出现然后在第一个用户迟来试图认领它们之前将它们呈现给另一个用户。when_presentedNULL

于 2012-12-23T15:53:09.017 回答
0

我添加了一个时间戳列和一个带有结构的额外表

Last_Oeration_Time(id number, last_op_time timestamp(6)) 

当第一个用户单击按钮时,我在 Last_Oeration_Time 上运行 sql 插入查询,例如 insert int Last_Oeration_Time(id,last_op_time) values(seq_lasst_op_time_id.nextval,sysdate)

现在,当第二个用户运行第一步时(假设自第一个用户运行以来又添加了两行),结果是期望的结果。这个可以吗?

于 2012-12-23T20:05:16.350 回答