我有一个Entity类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 = country,rootBeanClass = class com.foo.bar.Address, messageTemplate ='国家应该在那里'}
org.springframework.transaction.TransactionSystemException:无法 提交JPA事务;嵌套异常是 javax.persistence.RollbackException:提交时出错 交易
我尝试过使用try / catch块,但仍然无法捕获此异常。
注意:我已经将代码简化到最小程度,如果有遗忘或者我的问题不清楚则请问。
编辑:
完全堆栈stace
ERROR ExceptionMapperStandardImpl:39 - HHH000346:托管期间出错 flush [类验证失败 持续时间[com.foo.bar.Address] for groups [javax.validation.groups.Default,]约束列表 违规行为: ConstraintViolationImpl {interpolatedMessage ='国家应该在那里', propertyPath = country,rootBeanClass = class com.foo.bar.Address, 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) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect.Method.invoke(Method.java:498)at 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)at 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)at 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] for groups [javax.validation.groups.Default,]约束列表 违规行为: ConstraintViolationImpl {interpolatedMessage ='国家应该在那里', propertyPath = transactionId,rootBeanClass = class com.foo.bar.Address, 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个
答案 0 :(得分:0)
尝试捕捉PersistenceException
。此异常是一个包装异常,不会直接抛出。您可以使用ConstraintViolationException
方法提取已包装的getCause()
。
答案 1 :(得分:-1)
没有捕获ConstraintViolationException
的原因是存储库没有抛出该异常,而是抛出TransactionSystemException
,它有一个嵌套的ConstraintViolationException
实例。
有关捕获嵌套异常的详细信息,请参阅this question。