2014-02-17 164 views
0
沒有拋出異常

我有以下代碼:DB約束違反休眠

try { 
    userDAO1.save(userRecord); 
    userDAO2.save(userRecord); 
} 
catch(DataIntegrityViolationException e) { 
    throw new ApplicationException("Contraint violated") 
} 

userDAO1.save(userRecord)違反了完整性約束 - 所以整個代碼已運行後,沒有什麼寫入表userDAO1引用。

但是,userDAO1.save()語句不會引發錯誤/異常 - 因此也會執行userDAO2.save()。

但是DataIntegrityViolationException被捕獲,並且堆棧跟蹤爲空

如何檢查DataIntegrityViolationException從何處拋出,並防止在userDAO1.save()違反約束時執行userDAO2.save()?

我試着圍繞這段代碼添加一個@Transactional註釋,但那也沒用。

堆棧跟蹤:

org.springframework.dao.DataIntegrityViolationException: ORA-00001: unique constraint (UNIQUE_EMAIL) violated 
; SQL [n/a]; constraint [UNIQUE_EMAIL]; nested exception is org.hibernate.exception.ConstraintViolationException: ORA-00001: unique constraint (UNIQUE_EMAIL) violated 

    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:643) 
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:104) 
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:516) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754) 
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723) 
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393) 
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120) 
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
    at com.sun.proxy.$Proxy76.updateUser(Unknown Source) 
    at com.osiris.UserReg.UpdateUserCommand.execute(UpdateUserCommand.java:63) 

我已經發布的代碼是UpdateUserCommand,其中標註有@Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW)

+0

閱讀save()或persist()或merge()或在DAO.save()方法中調用的任何內容的javadoc。它不會告訴調用此方法時執行插入查詢。我非常懷疑堆棧跟蹤爲空。添加'e.printStackTrace()'到你的catch塊,你會看到它。並在您的ApplicationException中包裝DataIntegrityViolationException。 –

+1

與答案無關,但是您是否正在捕獲服務層中的DataIntegrityViolationException異常?看看您的代碼,看起來您正在這樣做。不是一個好主意。服務層與Dao層異常無關。 –

+0

我簡化了發佈目的的代碼 - 有一個單獨的業務層。 @Nizet - 我添加了一個printStackStrace(),唯一提到的類是內部的spring類 - 我寫的都沒有。 – Osiris

回答

3

好吧,這是有點棘手的一個,但我會盡我所能。 當@Transactional註釋的方法退出時,Hibernate只會提交一個事務。因此,DataIntegrityViolationException僅在該方法返回後纔可捕獲。沒有辦法讓Hibernate不能調用UserDAO2.save(),因爲它無法檢測到發生了違規行爲。我會在下面

@Service 
/*These variable names are used for clarity's sake, I don't actually use these names myself*/ 
public UserServiceImpl implements UserService{ 
    @Autowired 
    private HibernateUserDAO1 userDao1; 
    @Autowired 
    private HibernateUserDAO2 userDao2 

    @Transactional 
    /*Put your try catch block around where this method is called*/ 
    public void saveUserDao1(User user){ 
     userDao1.saveOrUpdate(user); 
    } 

    @Transactional 
    /*Only call this if saveUserDao1 succeeds*/ 
    public void saveUserDao2(User user){ 
      userDao2.saveOrUpdate(user) 
    } 
} 

然後一個例子,你HibernateUserDAO1:

public void saveOrUpdate(User user){ 
    currentSession().saveOrUpdate(user); 
} 

例外只能爲您服務層之上被抓。理想情況下,你想要做的是使用2個不同的DAO進行單獨保存,並檢查第一次成功之前做第二次。

編輯: 另外請注意,Hibernate不會選擇使用@Transactional註釋的私有方法,因爲Hibernate依賴於從您的類實現的接口創建Proxy對象。沒有接口定義=沒有代理對象=沒有休眠會話。所以你不能調用@Transactional註解的私有方法。我試圖讓你的SessionFactory成爲一個抽象超類中的一個對象,並且同時擁有這個DAO。更好的選擇是使用2個事務管理器,每個事務管理器指向不同的數據庫,然後指定哪些數據庫事物正在保存。這樣你可以只使用1個DAO,並使用你需要的會話工廠來完成你的保存。

+0

我發佈的代碼是用'@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)'註解的方法。 不應該還回滾userDAO2.save()語句嗎? – Osiris

+0

實際上你是否在使用2個不同的DAO,如果你是那麼userDAO2.save()將不會回滾,因爲它(通常)會有一個不同的SessionFactory實例,因此是一個不同的Session。 Hibernate將只會在導致異常的會話中回滾事務。 – JamesENL

+0

你可以發佈stacktrace所說的任何東西,以及你的服務層的相關摘錄,你的hibernate配置和這個工作的對象嗎? – JamesENL

0

是什麼讓你相信DataIntegrityViolationException沒有拋出,而聲明userDAO1.save ()被執行?另外,爲什麼您認爲userDAO2.save()也被執行?

如果上述觀點是在IDE調試控制檯(例如Eclipse的代碼執行進度)中觀察到代碼執行進度後做出的,那麼解釋可能是錯誤的。

請嘗試通過沖入一些調試語句(如下面的代碼)並執行代碼來觀察結果。這可以幫助你找出失敗的根本原因 -

try { 
    userDAO1.save(userRecord); 
    System.out.println("-- After userDAO1.save(userRecord) --"); 
    userDAO2.save(userRecord); 
    System.out.println("-- After userDAO2.save(userRecord) --"); 
} catch(DataIntegrityViolationException e) { 
    e.printStackTrace(); 
    throw new ApplicationException("Contraint violated") 
} 
+0

userDAO2指向的表中添加了新記錄。 我也試過在userDAO1.save()附近嘗試{} catch(Exception e){},但沒有發現異常。 – Osiris

+1

嗯......這可能是因爲Hibernate默認情況下只有當相應的** Transaction/Session對象被提交/關閉時才執行所需的SQL語句。因此,調用** save()**時不會拋出異常。請嘗試捕獲您提交或關閉事務或會話對象的異常。 –