[英]Process the multithreading in trigger
我必须在表事务中为每一行生成 number_order(顺序是:1、2、3...)。
我的解决方案是在插入表事务之前创建一个触发器。 触发器的任务是计算表的总行(select count(1) to v_count from Transaction)
--> 然后set :new.num_order = v_count + 1
。
该解决方案在几乎情况下运行正常,但是当系统有很多线程插入到表中时,触发器由多线程执行并且它们返回 SAME ORDER(原因是 select 命令在插入之前和同时被调用)。 你能给我建议一个替代解决方案吗? 提前谢谢你。
PS :我使用的是oracle 12c 数据库。 而且我不能使用序列,因为顺序实际上基于表中的其他一些列(例如: Room_id
)。 所以完整的选择命令是:
select count(1) to v_count from transaction where room_id = :new.room_id
通常,这是一种糟糕的方法,会导致显着的性能、扩展和支持问题。 我会重新考虑设计。
如果你想这样做,你需要强制你的交易序列化。 您可以有一个单独的表,主键为room_id
和room_count
值,或者您可以将该列添加到room
。 您需要通过select for update
锁定room_id
的行。 然后您将更新room_count
并将其用于您的insert
。 当您的事务提交时,锁将被释放。
但是,如果您这样做,涉及相同room_id
所有其他事务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
。
我将提出以下解决方案:新表
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;
/
在before insert
触发器中,您可以调用inc_room_cnt
来设置顺序:
:new.room_order := int_room_cnt(:new.room_id);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.