在触发器

时间:2016-09-16 09:24:41

标签: multithreading oracle triggers

我必须在表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)

2 个答案:

答案 0 :(得分:1)

通常,这是一种糟糕的方法,会导致严重的性能,扩展和支持问题。我会重新考虑设计。

如果要执行此操作,则需要强制事务序列化。您可以使用主键为room_idroom_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);