如何在提交期间捕获SQLExceptions?

时间:2016-01-30 21:57:23

标签: java spring hibernate jpa

使用Spring& JPA& Hibernate我使用方法来保存一些具有Exception处理的实体,如下所示:

@Repository
public class UserDAOImpl implements UserDAO {

    @PersistenceContext
    EntityManager em;

    @Override
        public void createUserRole(String role) throws RoleAlreadyExistsException {
            try {
                UserRole userRole = new UserRole(role);
                em.persist(userRole);
            } catch (Exception e) {
                throw new RoleAlreadyExistsException();
            }
        }
}

我的服务:

@Service("userService")
public class UserService 
    @Transactional
        public void createUserRole(String role) throws RoleAlreadyExistsException {
            userDao.createUserRole(role);
        }
}

稍后我实现了一些逻辑:

try{
     userService.createUserRole(role.name());
 }  catch (AuthorityEntityAlreadyExistsException e){}

但它没有捕获有关重复键的报告异常:

SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:259)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)

Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485)

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'ROLE_ADMIN' for key 'PRIMARY'
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)

所以,没有抛出我的RoleAlreadyExistsException,错过了catch块。在服务方法结束时在事务提交期间抛出异常。怎么抓住那个例外?或者如何以另一种方式在Spring中实现这个逻辑?

3 个答案:

答案 0 :(得分:0)

EntityManager.persist没有必要执行sql语句:新实体在缓存中注册,并在需要时发送到数据库。

如果数据库检查了您的约束,那么当该实体发送到数据库时,您会看到一个错误,在交易提交的最佳情况下:它是您在跟踪中看到的行为

您可以通过调用EntityManager.flush()

强制您的JPA实现将其缓存发送到数据库
public void createUserRole(String role) throws RoleAlreadyExistsException {
   try {
       UserRole userRole = new UserRole(role);
       em.persist(userRole);
       em.flush();
   } catch (Exception e) {
       throw new RoleAlreadyExistsException();
   }
}

然而,调用flush太多可能会导致性能下降,您应该在必要时调用它。分离DAO ans服务可能更简单:在UserService中尝试cach DataIntegrityException并且不要在DAO中调用flush

答案 1 :(得分:0)

对DAO或服务或控制器层使用@transactional注释,以便在提交期间捕获SQLexception时要回滚的方法。

i.e   @transactional
public void method(@param somevalue)
{
  // Database saving or updating function
  }

如果您希望在例外

期间显示特定消息 如果你想拥有特定expception类的全局处理程序

,请使用下面的代码
@ExceptionHandler(SQLException.class)      
public String exceptionMessage(){ //return exception message}

答案 2 :(得分:0)

1)DAO不应该捕获异常。让Hibernate或Spring生成的异常抛出而不管它。特别是如果您的异常转换非常广泛并且丢失信息(抛弃原始堆栈跟踪)。

2)不要依赖约束违规来告诉你有一个预先存在的条目。您可以在告诉Hibernate执行插入之前查询它。只要查询与插入在同一事务中,并且隔离级别是可重复读取或更好,查询结果将是可靠的。