2011-02-24 63 views
9

有沒有任何方法可以在約束違反異常被拋出後繼續使用線程綁定的hibernate會話?我給一個簡單的例子在這裏:ConstraintViolationException後Hibernate會話失效

Parent other=service.load(33); // loads a new parent 
    try { 
     Parent p=new Parent(); 
     p.setName("A name"); 
     service.save(p); // a @Transactional spring service class, throws ConstraintViolationException - name should be at least 15 characters long 
    } catch (ConstraintViolationException e){ 
     // i would like to handle validation errors and proceed normally 
     // but the session is allready closed here 
    } 
    System.out.println("Children: " + other.getChildren()); // lazy initialization exception, even when using opensessioninview 

從現在開始Hibernate的Session是完全無用的,甚至是隻讀喜歡用OpenSessionInView模式鑑於渲染延遲集合操作。

回答

12

Session的文檔指出如果會話引發異常,則必須回滾事務並丟棄會話。發生異常後,會話的內部狀態可能與數據庫不一致。。由於這些問題,我記得有人在工作時警告我不要使用session-per-request/OpenSessionInView-模式。

+0

這可能是正確的答案,但多麼令人不滿!在使用JPA(Hibernate 3)和Spring的應用程序中,我注意到當我們在合併之後顯式刷新實體管理器時拋出了'ConstraintViolationException異常,但如果我們移除了flush,則拋出了一個更通用的Spring'TransactionSystemException',其中包含嵌套的'RollbackException',它又包含根'ConstraintViolationException'。但是,在捕獲'TransactionSystemException'後,實體管理器(hibernate會話)仍然可用。沒有更多的懶惰初始化錯誤! – 2013-10-18 22:34:12

+1

@Brice:考慮到文檔明確指出在引發異常之後不使用Session,找到一個解決方法仍然使用它並不會降低危險性。它可能適用於某些情況而不適用於其他情況,導致不確定的行爲。但是,如果它對你沒有任何問題,那麼好!儘管如此,個人而言,我寧願不使用任何這樣的「噱頭」,而是首先解決交易中的問題(例如,在這個問題中,例如,以某種其他方式驗證輸入,而不是對數據庫進行驗證)。 – esaj 2013-10-19 11:57:41

+0

我同意。更清楚的是,這個問題與bean驗證(JSR 303)異常('javax.validation.ConstraintViolationException'而不是數據庫約束異常)有關,導致會話/實體管理器拋出一個異常使其本身無用。在pre-persist/pre-update/pre-remove驗證失敗後,仍然可以將會話用於只讀查詢將會很好。在這種情況下,在數據庫級別上沒有任何事情會使會話變得危險(據我所知),這僅僅是使某個實體無效的業務規則。 – 2013-10-21 20:24:43

5

使用StatelessSession而不是Session。這是一個竅門。

使用StatelessSession,您可以在任何異常之後繼續執行,因爲它可能在SQL中(甚至在一個事務中 - 沒有提交/回滾由休眠完成)。這對批量更新/插入或檢查是否違反唯一約束是理想的。

但請注意,與普通會話相比,StatelessSession有許多限制。請參閱Hibernate文檔/ Javadocs。

+0

適合我! (到目前爲止) – displayname 2015-05-29 14:54:36

+0

謝謝。工作。我只需要插入,它的工作。 – Bhaskara 2015-09-08 07:06:46