我们有一个before insert触发器,它从序列中获取下一个值。当使用save()方法持久化对象时,hibernate从序列中获取值并将其添加到对象中。当从Spring的服务层提交事务时,数据库上的ID值再次增加。如果对象已经有id ..
,如何避免获取nextval()这是我想做的事情..
userDAO的
public User saveUser(User user){
session.getCurrentSession.save(user);//line2
return user;//line3
}
UserService
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。在line2之后,它有来自序列的nextval - 让我们说1.在第4行,我已将用户的id = 1添加到useraudit对象..当事务在第5行之后提交时,2被插入到User的id列中,1被插入到UserAudit的userId列中。这对我没有任何意义:(我如何避免这个问题?谢谢!
答案 0 :(得分:10)
只需将您的触发器更新为仅在未给出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;
答案 1 :(得分:5)
上面的解决方案很棒,这让我对这个问题感到很头疼。
我唯一的抱怨是打开用户/代码的大门,插入任何ID值而不实际询问序列。
我发现以下解决方案也有效。它允许Hibernate找到最大ID,并在每次执行insert语句时使其递增。但是当它到达数据库时,ID被忽略并被触发器生成的ID替换,因此没有uniqueness in a cluster problem:
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
private Long id;
最大的缺点是@GenericGenerator是一个Hibernate注释,因此你失去了JPA的可移植性。程序员也不清楚这个ID实际上是否与一个序列相关联,而事实上,它是使用序列的最紧密耦合解决方案之一。
答案 2 :(得分:0)
理想情况下,你会删除BEFORE INSERT TRIGGER。如果不这样做,Hibernate无法知道主键,它确实需要这些信息。如果您在INSERT之后不关心对象可能没问题(二级缓存仍然是个问题),但是如果您需要立即使用它,那么这是一个真正的问题。在后一种情况下,你可以尝试这种讨厌的方法:
答案 3 :(得分:0)
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,你的hibernate框架可以正常工作。但是如果有人直接使用你的主键值插入jdbc作为66覆盖序列(比如当前值为52),触发器就会插入。
真正的问题是当序列值增加到66时,这会在触发器中引发异常,从而重置序列值。这真的以数据库方面的架构设计结构糟糕而告终。