我必须在表Transaction中为每一行生成number_order(顺序为:1,2,3 ......)。我的解决方案是在插入表Transaction之前创建一个触发器。触发器的任务是计算表的总行数(从事务中选择count(1)到v_count) - >然后设置:new.num_order = v_count + 1。
该解决方案在几乎情况下运行正常,但是当系统有许多线程插入到表中时,触发器由多线程执行并且它们返回SAME ORDER(原因是select命令被称为同时和插入之前)。 你能告诉我一个替代解决方案吗?先感谢您。 P / s:我正在使用oracle 12c数据库。我不能使用序列,因为顺序实际上基于表中的其他一些列(例如:Room_id)。所以完整的select命令是:select transaction(1)to v_count from transaction where room_id =:new.room_id)
答案 0 :(得分:1)
通常,这是一种糟糕的方法,会导致严重的性能,扩展和支持问题。我会重新考虑设计。
如果要执行此操作,则需要强制事务序列化。您可以使用主键为room_id
和room_count
的单独表格,也可以将该列添加到room
。您需要通过room_id
锁定select for update
的行。然后,您将更新room_count
并将其用于insert
。当您的事务提交时,锁将被释放。
但是,如果执行此操作,则涉及相同room_id
的所有其他事务都将被阻止。如果您的交易时间相对较短,那么假设您没有太多用户使用同一个房间,这可能并不可怕。然而,随着用户数量和交易时间的增加,问题变得更加困难。如果交易涉及多个房间,则您需要每个交易以相同的顺序处理它们(例如,以room_id
顺序)以避免潜在的死锁。如果你打算做的不仅仅是这个表,那么事情会变得更加复杂。
我更愿意使用序列,然后在查询中生成顺序值。例如
SELECT room_id,
rank() over (partition by room_id order by sequence_column) your_num_order
FROM your_table
或者您可以使用sequence_column
进行初始插入,并定期进行后台作业(每日常见),并在事务完成后分批指定num_order
。
答案 1 :(得分:-1)
我建议以下解决方案: 新表
create table room_count( room_id NUMBER primary key, cnt number);
增加自治事务中计数的函数:
Create or replace function inc_room_cnt( p_room_id NUMBER) return number as
PRAGMA autonomous_transaction;
v_cnt NUMBER;
begin
update room_count set cnt = cnt +1 where room_id = p_room_id returning cnt into v_cnt;
-- insert new room if not yet exists
if SQL%ROWCOUNT = 0 then
v_cnt := 1;
insert into room_count values (p_room_id, v_cnt);
end if;
commit;
return v_cnt;
end;
/
<{1>}在before insert
触发器中,您可以调用inc_room_cnt
来设置订单:
:new.room_order := int_room_cnt(:new.room_id);