一尘不染

Spring Rest中的ConstraintViolationException

hibernate

我有下一个spring rest控制器来处理我的异常:

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public @ResponseBody
ExceptionResponseDTO hiberAnnotationExceptionHandler(ConstraintViolationException exception) {
    return  new ExceptionResponseDTO("Entity is null or we are out of range!", exception.getMessage(), ExceptionMapper.INSTANCE.exceptionToExceptionDTO(exception));
}

我的 实体 类:

@Entity
public class Device {

    @Id
    @Column(name="name", nullable = false)
    private String Name;

    @Column(name = "send_date")
    @NotNull
    private Date sendDate;
}

我尝试模拟 ConstraintViolationException ,因此在我的控制器中使用下一个代码:

Device d = new Device();
d.setName("sdsdsd");
d.setSendDate(null);
deviceRepository.save(d);

结果,我收到下一个异常:

[dispatcherServlet] :?-路径为[]的上下文中的Servlet
[dispatcherServlet]的Servlet.service()抛出异常[请求处理失败;嵌套的异常是org.springframework.transaction.TransactionSystemException:无法提交JPA事务。嵌套的异常是javax.persistence.RollbackException:根本原因提交事务时出错,原因是javax.validation.ConstraintViolationException:组[javax.validation.groups.Default,]的更新期间,对类[com.entity.Device]的验证失败违反约束的列表:[ConstraintViolationImpl
{interpolatedMessage =’可能不为空’,propertyPath = sendDate,rootBeanClass = class
com.entity.Device,messageTemplate
=’{javax.validation.constraints.NotNull.message}’}]

因此,从 堆栈跟踪中 可以看到,我首先收到 TransactionSystemException ,因此,我的
ExceptionHandler 方法( hiberAnnotationExceptionHandler )不被调用。所以我的问题是如何模拟此异常(
ConstraintViolationException )?提前致谢。


阅读 1364

收藏
2020-06-20

共1个答案

一尘不染

TransactionSystemException的原因

  1. hibernate实体管理器负责引发所有hibernate异常

如果您进入代码AbstractEntityManagerImpl.convert()方法,您将看到默认情况下它不处理任何特定的异常(如ConstraintViolation),而是仅抛出并包装PersistenceException。

  1. 如果您在@Transaction中调用代码并将其转换为TransactionSystemException,则JPA事务管理器会捕获上述异常,您可以看到spring JPA事务管理器的代码class =“ org.springframework.orm.jpa.JpaTransactionManager”

正确解决异常的解决方案

  1. 首先注册一个JPA方言,它可以拦截那些HibernateExceptions并包装到特定的Spring异常中,例如在事务管理器bean中。
>      <bean id="transactionManager"
> class="org.springframework.orm.jpa.JpaTransactionManager">
>         <property name="entityManagerFactory" ref="entityManagerFactory"/>
>         <property name="jpaDialect" ref="jpaDialect"/>
>     </bean>
>  
>     <bean id="jpaDialect"
> class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>

HibernateJpaDialect捕获这些异常并将其转换为Spring特定的异常,如下所示

>     if (ex instanceof ConstraintViolationException) {
>               ConstraintViolationException jdbcEx =
> (ConstraintViolationException) ex;
>               return new DataIntegrityViolationException(ex.getMessage()  +
> "; SQL [" + jdbcEx.getSQL() +
>                       "]; constraint [" + jdbcEx.getConstraintName() + "]",
> ex);
>           }
  1. 您还可以注册您的entitymanager正在使用hibernatejpaVendorAdapter来确保您在任何地方都使用hibernate。
>     <bean id="entityManagerFactory"
> class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
>           <property name="packagesToScan" value="com.pack.model" />
>             <property name="persistenceUnitManager"
> ref="persistenceUnitManager"/>
>             <property name="persistenceUnitName" value="entityManager"/>
>             <property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
>         </bean>    <bean id="jpaVendorAdapter"
> class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
  1. 现在在您的控制器中,您可以期待dataIntegrityException,它是由于ConstraintViolationException而抛出的hibernate方言产生的

@ExceptionHandler(DataIntegrityViolationException.class)

2020-06-20