【问题标题】:Unable to catch TransactionSystemException无法捕获 TransactionSystemException
【发布时间】:2018-11-20 14:15:35
【问题描述】:

我有一个实体类 Person,它通过 JoinColumn 连接到另一个实体 Address 并与 Person 具有 OneToOne 关系,Address 实体在字段 country 上有一个 @NotNull 注释。

简化代码如下:

@Entity
public class Person {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long PersonId; 

@Valid
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
@JoinColumn(name = "address_id")
private Address address;
....
..some more fields, getters and setters etc..
...
}

地址实体如下:

@Entity
public class Address {

@Id
@GeneratedValue
private Long addressId;

private String street;

@NotEmpty(message = "Country should be there")
private String country;

....some more fields and getters and setters etc ....
}

除此之外,我还有一个 PersonRepository。

我还有一个服务方法,即updateAddress,该方法的最简单形式如下:

public class Service {

@Transactional
public void updateAddress(Long personId, Address address) {
try {
Person original = findPersonById(personId);

...some validations etc ....

original.setAddress(address);            
personRepository.save(original);
} catch (ConstraintViolationException e) {

    }
}

我编写了一个小型单元测试,我尝试使用 updateAddress 方法为没有预定义地址的人更新地址。

@Test
void checkUpdateAddress() {
Person person = new Person();
.....initiate some fields, except address ....
Long personId =personRepository.save(person);

Address address = new Address();
address.street("abcd");

service.updatePerson(personId, address);
//assertions etc
}

问题是我得到了

引起:javax.validation.ConstraintViolationException:验证 类 [com.foor.bar.Address] 失败 在组的持续时间内 [javax.validation.groups.Default, ] 约束违规列表:[ ConstraintViolationImpl{interpolatedMessage='国家应该在那里', propertyPath=国家,rootBeanClass=类 com.foo.bar.地址, messageTemplate='国家应该有'}

org.springframework.transaction.TransactionSystemException: 不能 提交 JPA 事务;嵌套异常是 javax.persistence.RollbackException:提交时出错 交易

我尝试过使用 try/catch 块,但仍然无法捕获此异常。

注意:我已将代码简化到最低限度,如果有什么我忘记了或者我的问题不清楚,请询问。

编辑:

全栈

ERROR ExceptionMapperStandardImpl:39 - HHH000346: 托管期间出错 flush [类的验证失败 [com.foo.bar.Address] 在持续时间内 对于组 [javax.validation.groups.Default, ] 约束列表 违规行为:[ ConstraintViolationImpl{interpolatedMessage='国家应该在那里', propertyPath=国家,rootBeanClass=类 com.foo.bar.地址, messageTemplate='国家应该有'} ]]

org.springframework.transaction.TransactionSystemException: 不能 提交 JPA 事务;嵌套异常是 javax.persistence.RollbackException:提交时出错 交易

在 org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:545) 在 org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746) 在 org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714) 在 org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:532) 在 org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304) 在 org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) 在 org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689) 在 com.foo.bar.service.Service$$EnhancerBySpringCGLIB$$57d9106c.updateAddress() 在 com.rfoo.bar.service.MyTest.checkUpdateAddressMethod(MyTest.java:956) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498) 在 org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:436) 在 org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170) 在 org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113) 在 org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:112) 在 org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) 在 java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) 在 java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) 在 java.util.Iterator.forEachRemaining(Iterator.java:116) 在 java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) 在 java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) 在 java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) 在 java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) 在 java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) 在 java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) 在 java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) 在 org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$2(HierarchicalTestExecutor.java:120) 在 java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184) 在 java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) 在 java.util.Iterator.forEachRemaining(Iterator.java:116) 在 java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) 在 java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481) 在 java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471) 在 java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) 在 java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) 在 java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) 在 java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.lambda$executeRecursively$3(HierarchicalTestExecutor.java:120) 在 org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.executeRecursively(HierarchicalTestExecutor.java:108) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$NodeExecutor.execute(HierarchicalTestExecutor.java:79) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:55) 在 org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43) 在 org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170) 在 org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154) 在 org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90) 在 com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74) 在 com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) 在 com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) 在 com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 引起:javax.persistence.RollbackException:提交时出错 交易在 org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:77) 在 org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:71) 在 org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:536) ... 63 更多原因:javax.validation.ConstraintViolationException: 类的验证失败 [com.foo.bar.Address] 在持续时间内 对于组 [javax.validation.groups.Default, ] 约束列表 违规行为:[ ConstraintViolationImpl{interpolatedMessage='国家应该在那里', propertyPath=transactionId, rootBeanClass=class com.foo.bar.地址, messageTemplate='国家应该在那里'}] 在 org.hibernate.cfg.beanvalidation.BeanValidationEventListener.validate(BeanValidationEventListener.java:140) 在 org.hibernate.cfg.beanvalidation.BeanValidationEventListener.onPreInsert(BeanValidationEventListener.java:80) 在 org.hibernate.action.internal.EntityInsertAction.preInsert(EntityInsertAction.java:205) 在 org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:82) 在 org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:600) 在 org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:474) 在 org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337) 在 org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) 在 org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1436) 在 org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:493) 在 org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3206) 在 org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2412) 在 org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473) 在 org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:156) 在 org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) 在 org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231) 在 org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:68) ... 64 更多

【问题讨论】:

  • 你的@Service注解在哪里?没有必要吗?
  • @R.A.Munna 不,没有必要
  • 一旦你发现异常你又抛出它......为什么???
  • 我的错误,复制/粘贴错误
  • 那么当你有一个通用的catch块时,抛出的异常类型是什么?

标签: java spring-boot jpa


【解决方案1】:

尝试捕捉PersistenceException。这个异常是一个包装的异常,不会直接抛出。您可以使用getCause() 方法提取包装好的ConstraintViolationException

【讨论】:

    【解决方案2】:

    ConstraintViolationException 没有被捕获的原因是存储库没有抛出那个异常,它抛出了 TransactionSystemException,它有一个嵌套的 ConstraintViolationException 实例。

    有关捕获嵌套异常的更多信息,请参阅this question

    【讨论】:

    • 试图捕捉 TransactionSystemException 但没有帮助。
    • 你有完整的堆栈跟踪吗?
    • 已添加,请查看
    • 'ConstraintViolationException 未被捕获的原因是存储库没有抛出该异常,而是抛出了TransactionSystemException'。嗯……不。 ConstraintViolationException 没有被捕获的原因是存储库没有抛出任何异常根本,因为验证只发生在事务提交时,即之后 updateAddress结束
    猜你喜欢
    • 2015-07-24
    • 1970-01-01
    • 1970-01-01
    • 2012-08-08
    • 2012-11-09
    • 2011-03-14
    • 2012-03-15
    • 2014-11-25
    • 1970-01-01
    相关资源
    最近更新 更多