处理@Transactional类中的异常

时间:2014-08-23 13:37:41

标签: java spring hibernate

在我的Spring托管类(@Transactional@Service注释)中,我有以下方法:

@Transactional
@Service
public class Foo {

    @Autowired
    private MyService service; // MyService has @Service and @Transactional annotations


      public void save(...) { 
          try { 
              service.save(...); // gets a Hibernate Session & calls `merge(...)`
          } catch(DataIntegrityViolationException e) {
             logMessage("save failed with exception: " + e);
          }
      }

在我的相应表格中(Foo#save执行了保存工作),我有一个unique constraint

当上述Foo#save代码以违反唯一约束的方式执行时,我在日志中看到抛出了DataIntegrityViolationException,但它没有被我抓住Foo#save' catch阻止。

   org.springframework.orm.jpa.JpaTransactionManager 891 doRollbackOnCommitException - 
     Initiating transaction rollback after commit exception 
   org.springframework.dao.DataIntegrityViolationException: Could not execute 
       JDBC batch update; SQL [insert into MY_TABLE ...; constraint 
         [MY_CONSTRAINT]; nested exception is 
       org.hibernate.exception.ConstraintViolationException: Could not execute 
    JDBC batch update

感到困惑的是DataIntegrityViolationException未被捕获,我为所有RuntimeException添加了另一个捕获:

      public save(...) { 
          try { 
              service.save(...); // `service` is marked with 
                                 //  @Service and @Transactional
          } catch(DataIntegrityViolationException e) {
             logMessage("save failed with exception: " + e);
          } catch(RuntimeException e) {
             logMesssage("runtime exception e: " + e);
          }
      }

但是,当我运行违反唯一约束违规的相同代码时,我没有看到来自catch(RuntimeException e)块的日志消息。

我的不完全理解是,由于我使用@TransactionalFoo(由Spring创建)的代理将执行save方法调用。

但是,我有可能抓住DataIntegrityViolationException调用的service.save(...)吗?

1 个答案:

答案 0 :(得分:1)

方法session.merge(...)不会立即执行插入/更新SQL查询,而是将此操作放入队列中。会话刷新时将执行SQL查询。在您的情况下,在您的方法执行后,会话将在事务性建议中刷新,并且异常将被抛出。

因此,要在方法中捕获异常,请在session.flush()之后添加session.merge(...),如下所示:

  public class MyService {

      public void save(Object o) {
         Session session = //get session somehow
         session.merge(o);
         session.flush();  // In case of data integrity violation Exception will be thrown here
      }
  }