数据库约束违规不会在Hibernate中抛出exception

我有以下代码:

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

userDAO1.save(userRecord)违反了完整性约束 – 因此在运行整个代码之后,userDAO1引用的表中没有任何内容写入。

但是,userDAO1.save()语句不会抛出错误/exception – 因此也会执行userDAO2.save()。

但是捕获了DataIntegrityViolationException,并且堆栈跟踪为null

如何检查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)注释@Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW)

好吧,这有点棘手,但我会尽我所能。 Hibernate只会在使用@Transactional注释的方法退出时提交事务。 因此,只有在该方法返回后才能捕获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); } 

只能在服务层之上捕获exception。 理想情况下,您想要做的是使用2个不同的DAO进行单独保存,并在执行第二个DAO之前检查第一个成功。

编辑:还要注意Hibernate不会选择使用@Transactional注释的私有方法,因为Hibernate依赖于从类实现的接口创建Proxy对象。 没有接口定义=没有代理对象=没有Hibernate会话。 因此,您无法调用使用@Transactional注释的私有方法。 我试着让你的SessionFactory成为一个抽象超类中的对象,并让DAOinheritance这个。 更好的选择是使用2个事务管理器,每个事务管理器指向不同的数据库,然后指定哪些数据库也可以保存。 这样你就可以只使用1个DAO,并使用你需要的任何会话工厂来进行保存。

是什么让你相信在执行语句userDAO1.save()时没有抛出DataIntegrityViolationException ? 另外,为什么你认为语句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") }