2014-02-17 126 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()**时不会抛出异常。请尝试捕获您提交或关闭事务或会话对象的异常。 –