oracle中触发器问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了oracle中触发器问题相关的知识,希望对你有一定的参考价值。

CREATE OR REPLACE TRIGGER BI_WARE_STOCK2
BEFORE DELETE
ON WARE_STOCK
FOR EACH ROW
DECLARE COUNTS INT;
BEGIN
SELECT W_STO.N_STOCK_COUNTS INTO COUNTS
FROM WARE_STOCK W_STO WHERE :NEW.VC_WARE_ID = W_STO.VC_WARE_ID
AND W_STO.VC_DOCUMENT_ID = :NEW.VC_DOCUMENT_ID;
END;

对一个表建触发器时如何在该触发器中获取表中以前的数据?
急!
盼高人指点!

你是想获取被删除的数据么?如果是它是放在 old 里面的。

例如:
--创建一个delete类型行级触发器
--删除的一行数据保存在:old
create or replace trigger emp_delete_row_trigger
after delete
on emp
referencing new as n old as o
for each row
begin
dbms_output.put_line('emp_delete_row_trigger called.');
dbms_output.put_line('删除员工:' || :o.empno || ' ' || :o.ename);
end;

说明:
【referencing new as n old as o】是给【new】和【old】起别名,下面引用的【:o.empno】就是被删除的那条记录的 【empno】

---
以上,希望对你有所帮助。
参考技术A 就是在触发器就使用“:old.列名”来获取值
看你的select语句中怎么会有:NEW.VC_WARE_ID
对于delete触发来说,是没有:new这个值的
同理对于insert来说,是没有:old的
参考技术B 对于你是删除行触发,没什么新旧之分啊,update才有。

用于从序列生成 id 的 Oracle 触发器的 HIbernate 问题

【中文标题】用于从序列生成 id 的 Oracle 触发器的 HIbernate 问题【英文标题】:HIbernate issue with Oracle Trigger for generating id from a sequence 【发布时间】:2011-12-21 13:46:55 【问题描述】:

我们有一个插入前触发器,可以从序列中获取下一个值。当对象使用 save() 方法持久化时,hibernate 从序列中获取值并将其添加到对象中。当事务从 Spring 的服务层提交时,ID 值在数据库上再次增加。如果对象已经有一个 id,我如何避免得到 nextval() ..

这就是我想做的事情..

用户道

public User saveUser(User user)
      session.getCurrentSession.save(user);//line2
      return user;//line3  
 

用户服务

public void saveUserAndWriteToAudit(User user, UserAudit userAudit)
  userDao.saveUser(user);//line1
  userAudit.setUserId(user.getId);//line4
  userAudit.saveUserAudit(userAudit);//line5

还有用户类

 @Entity
  public class User

     @Id
     @GeneratedValue(strategy=GenerationType.AUTO, generator="a1")
     @SequenceGenerator(name="a1", sequenceName="usersequence")
     private Long id;
     /////////////////
 

当光标到达 line1 并且 line2 用户对象的 id 属性为 null 时。在第 2 行之后,它具有序列中的下一个值 - 比如说 1。在第 4 行,我已将用户的 id=1 添加到 useraudit 对象。当在第 5 行之后提交事务时,将 2 插入到用户的 id 列中,将 1 插入到 UserAudit 的 userId 列中。这对我没有任何意义:(我该如何避免这个问题?谢谢!

【问题讨论】:

【参考方案1】:

只需将您的触发器更新为仅在未指定 ID 时触发。

create or replace
trigger sa.my_trigger
before insert on sa.my_table
for each row
when (new.id is null)
begin
   select sa.my_sequence.nextval
    into :new.id
    from dual;
end;

【讨论】:

试过了,但是当我从 JPA 进行一些插入,然后通过 SQL 进行一些插入时,序列不是最新的,并且在使用 SQL 时出现“违反唯一约束”。我在实体中有@GeneratedValue@SequenceGenerator 注释。【参考方案2】:

上面的解决方案很棒,它让我在这个问题上省了很多麻烦。

我唯一的抱怨是它为用户/代码打开了插入任何 ID 值而不实际查询序列的大门。

我发现以下解决方案也有效。它让 Hibernate 找到最大 ID 并在每次执行插入语句时增加它。但是当它到达数据库时,ID被忽略并被触发器生成的ID替换,因此没有uniqueness in a cluster problem:

    @Id
    @GeneratedValue(generator="increment")
    @GenericGenerator(name="increment", strategy = "increment")
    private Long id;

最大的缺点是@GenericGenerator 是一个Hibernate 注解,所以你失去了JPA 的可移植性。程序员也不清楚这个 ID 实际上是链接到一个序列,而事实上,它是使用序列的最紧密耦合的解决方案之一。

【讨论】:

感谢 Christopher,我一直在努力使用数据库触发器来填充主键,这解决了问题。 这也适用于我。无需更改 Oracle DB 中的 DB 触发器。非常感谢! 已更新!在我收到“违反唯一约束”错误之前,这一切正常。如前所述,执行此操作后 DB 序列不同步。同样在同一个表中插入数据的 Web 服务出现错误,因为 nextval 正在获取一个已经存在的值。【参考方案3】:

理想情况下,您应该删除 BEFORE INSERT TRIGGER。如果你不这样做,Hibernate 就无法知道主键,它确实需要这些信息。如果您不关心 INSERT 之后的对象,那可能没问题(二级缓存仍然是一个问题),但如果您需要立即使用它,那就是一个真正的问题。在后一种情况下,您可以尝试这种讨厌的方法:

    告诉 Hibernate 您自己管理主键。 创建新对象并将任意值放入主键。 刷新您的 Hibernate 会话和 SELECT sequence.CURRVAL(假设只有一个 INSERT)。 使用获取的当前序列值加载对象,不要使用上面的实例。

【讨论】:

@FelixM.. 感谢您的回复.. 如果我们修改触发器以检查 :new.id=null 与否,这行得通吗?.. 我无法测试它,因为我没有 db修改触发器的权限..在要求 dba 修改它之前,我需要确保它足够 如果您按照其他响应中的说明修改触发器,则可以告诉 Hibernate 使用该序列。【参考方案4】:
create or replace
trigger sa.my_trigger
before insert on sa.my_table
for each row
when (new.id is null)
begin
   select sa.my_sequence.nextval
    into :new.id
    from dual;
end;

这在数据库世界中确实有问题。

考虑到上述解决方案,假设 sa.my_sequence.nextval 为 51,您的休眠框架将毫无问题地工作。但是,如果有人使用您的主键值作为 66 覆盖序列(例如,当前值为 52)进行直接 jdbc 插入,则触发器只会插入。

真正的问题是当序列值增加到 66 时,这将在触发器中引发异常,以重置序列值结束。这实际上以数据库方面的架构设计结构不良而告终。

【讨论】:

以上是关于oracle中触发器问题的主要内容,如果未能解决你的问题,请参考以下文章

获取触发 Oracle 触发器的值

oracle触发器中定时执行sql

oracle触发器查询中的问题

如何在 Oracle 中定义一个触发器 ON COMMIT?

Oracle 触发器调试及遇到相关问题解决

oracle 触发器 问题