我有一个数据库表,记录其他表中发生的更改。我的日志表的表结构如下。
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);
请建议我该怎么做?在选择行之后,我需要为任何类型的操作锁定行。我尝试选择更新子句,但它没有解决问题。它在一个Web应用程序中。
答案 0 :(得分:1)
在等待用户输入时保持数据库事务处于打开状态几乎绝不是一个好主意。如果用户在交易未决时去吃午餐,或者他们的网络连接中断并且几天没有恢复,该怎么办?
此外,您没有说明您正在使用的数据库产品。根据产品,其配置和事务隔离级别,并发尝试的结果是事务挂起的内容,因此如果您想要可移植行为,则不能依赖SELECT FOR UPDATE
的行为或甚至更标准化的行为特征
我的建议是在行中提供一种方法来识别等待用户确认的待处理行。您可以在flag
列中使用三种状态来表示available
,pending
和taken
之类的内容;但是,您可能想要某种方式来识别呈现给用户的行,但用户从未单击“确定”或“取消”(或任何选项)。如果为此目的添加时间戳列,则可以使用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_presented
设置回NULL
,然后在第一个用户迟迟尝试声明它们之前呈现给另一个用户,则关闭竞争条件。
答案 1 :(得分:0)
我添加了一个timestamps列和一个带结构
的额外表Last_Oeration_Time(id number, last_op_time timestamp(6))
当第一个用户单击该按钮时,我在Last_Oeration_Time上运行一个sql insert查询 insert int Last_Oeration_Time(id,last_op_time)values(seq_lasst_op_time_id.nextval,sysdate)
现在当第二个用户运行第一步时(假设自第一个用户运行以来已经添加了两行),结果是所需的结果。这样可以吗?