java - 在 Hibernate 中数据库约束违规不会抛出异常

标签 java spring hibernate jpa

我有以下代码:

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)

最佳答案

好吧,这有点棘手,但我会尽力而为。 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);
}

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

编辑: 另请注意,Hibernate 不会选择用 @Transactional 注释的私有(private)方法,因为 Hibernate 依赖于从类实现的接口(interface)创建 Proxy 对象。没有接口(interface)定义=没有代理对象=没有Hibernate Session。所以你不能调用带有@Transactional注解的私有(private)方法。我会尝试使您的 SessionFactory 成为抽象父类(super class)中的对象,并让两个 DAO 都继承于此。更好的选择是使用 2 个事务管理器,每个事务管理器都指向不同的数据库,然后指定要保存的数据库内容。这样您就可以只使用 1 个 DAO,并使用您需要的任何 session 工厂来进行保存。

关于java - 在 Hibernate 中数据库约束违规不会抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21822663/

相关文章:

java - curl 相当于 -u

java - 获取通用基础存储库的参数类型名称

java - 您如何在蓝/绿部署中管理共享数据库?

java - HttpSecurity permitAll 和 WebSecurity 忽略未验证 URL 的功能?

java - 如何让 hibernate 删除一张 table 而离开另一张 table ?

java - 配置 Hibernate 以使用 JPA 风格的配置,而无需进入 EE

java - 如何读取 ws-security 中提供的用户或标识符

java - 如何使用 org.osgi.service.prefs.Preferences.clear()