2011-11-03 38 views
7

我們有一個before插入觸發器,用於從序列中獲取下一個值。當對象用save()方法持久化時,hibernate從序列中獲取值並將其添加到對象中。當事務從Spring的服務層提交時,數據庫上的ID值再次增加。如何避免讓NEXTVAL()如果對象已經有一個id ..用於從序列中生成id的Oracle觸發器的HIbernate問題

這裏是我是個嘗試做..

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之後,它具有sequence的nextval - 讓我說1在line4上,我已經添加了用戶的id = 1來使用審查對象..當事務在第5行後被提交時,2被插入到用戶的id列中並且1被插入到UserAudit的userId列中。這對我來說沒有任何意義:(如何避免這個問題?謝謝!

回答

9

只是更新你的觸發器,只有在沒有給出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; 
+0

感謝馬修.. – RKodakandla

0

理想情況下,你會刪除BEFORE INSERT TRIGGER。如果你不這樣做,Hibernate無法知道主鍵,它真的需要如果你不關心INSERT之後的對象可能是好的(二級緩存仍然是一個問題),但是如果你需要馬上使用它,這是一個真正的問題,在後一種情況下,你可以試試這個討厭的做法:

  1. 告訴Hibernate是你自己管理的主鍵
  2. 創建新的對象,並把一個任意值到主鍵
  3. 刷新你的Hibernate會話和SELECT sequence.CURRVAL(假設只有一個INSERT)。
  4. 使用獲取的當前序列值加載對象,但不使用上述實例。
+0

@FelixM ..謝謝你的回覆..如果我們修改觸發器來檢查:new.id = null或不,我會不會測試它,因爲我沒有db特權來修改觸發器在要求dba修改它之前,我需要確保它足夠。 – RKodakandla

+0

如果按照其他響應中所述修改觸發器,則可以讓Hibernate使用該序列。 – FelixM

5

上述解決方案非常棒,它爲這個問題節省了很多麻煩。

我唯一的抱怨是它打開了用戶/代碼插入任何ID值沒有實際查詢序列的大門。

我發現以下解決方案也適用。它讓Hibernate找到最大ID並在每次執行插入語句時增加它。但是,當它訪問數據庫,該ID將被忽略,由觸發產生的一個替代,所以沒有uniqueness in a cluster problem

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

最大的缺點是@GenericGenerator是Hibernate的註解,讓你失去了JPA的便攜性。程序員也不清楚這個ID是否與一個序列實際相連,而事實上,它是使用序列的最緊密的耦合解決方案之一。

+0

謝謝克里斯託弗,我一直在努力使用數據庫觸發器填充主鍵,這解決了這個問題。 – user75ponic

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時,這會引發觸發器中的異常,並在重置序列值時結束。這確實從數據庫方面結束了架構設計的糟糕結構。