JPA RollbackException持久化事务导致后续有效事务失败?

我有一个@Transactional服务在oracle DB中执行持久化操作。 如果我运行一个持久化程序打破一个唯一的违规,我得到预期的rollbackException:ConstraintException。

问题是任何后续请求(即使不破坏唯一约束)持久化都会引发相同的exception。

似乎JPA没有清除对象以保持其事务管理器? 我甚至关闭? 我需要一点解释。

回购:

@Repository public class UserRepository { @PersistenceContext(type=PersistenceContextType.EXTENDED) private EntityManager em; public User findUserById(long id){ CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery query = builder.createQuery(User.class); Root root = query.from(User.class); Predicate whereClause = builder.equal(root.get(User_.userId), id); return em.createQuery(query.where(whereClause)).getSingleResult(); } public User findUserByCredentials(String credentials){ CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery query = builder.createQuery(User.class); Root root = query.from(User.class); Predicate whereClause = builder.equal(root.get(User_.credentials), credentials); return em.createQuery(query.where(whereClause)).getSingleResult(); } public void registerUser(User user){ em.persist(user); } } 

ServiceImpl:

 @Transactional(readOnly=true) @Service("userService") public class UserServiceImpl implements UserService { @Resource private UserRepository userRepository; public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } public User findUserById(long id) { return userRepository.findUserById(id); } public User findUserByCredentials(String credentials){ return userRepository.findUserByCredentials(credentials); } @Transactional(readOnly=false) public void registerUser(User user){ userRepository.registerUser(user); } } 

端点错误抛出:

 @PayloadRoot(localPart="RegisterUserRequest", namespace = "http://www.missingwire.com/schemas/User") public RegisterUserResponseDocument registerUser(RegisterUserRequestDocument requestDoc){ RegisterUserRequest request = requestDoc.getRegisterUserRequest(); User user = new User(); user.setCredentials(request.getCredentials()); user.setPassword(request.getPassword()); user.setHonorRating(BigDecimal.valueOf(STARTING_USER_HONOR_RATING)); user.setAccountActive(true); user.setDateCreated(new Date()); user.setVerified(false); UserProfile userProfile = new UserProfile(); userProfile.setEmailAddress(request.getEmail()); userProfile.setFirstName(request.getFirstName()); userProfile.setLastName(request.getLastName()); userProfile.setDateCreated(new Date()); userProfile.setUser(user); user.setUserProfile(userProfile); **userService.registerUser(user);** //HERE IS THE EXCEPTION THROW RegisterUserResponseDocument responseDoc = RegisterUserResponseDocument.Factory.newInstance(); RegisterUserResponse response = responseDoc.addNewRegisterUserResponse(); UserType userType = response.addNewUser(); userType.setAccountActive(user.getAccountActive()); userType.setCredentials(user.getCredentials()); userType.setDateCreated(DateConverter.convertDateToXML(user.getDateCreated())); userType.setUserId(user.getUserId()); userType.setVerified(user.getVerified()); return responseDoc; } 

例外:

org.springframework.orm.jpa.JpaSystemException:提交事务时出错; 嵌套exception是javax.persistence.RollbackException:在org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect)的org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:311)中提交事务时出错。在org.springframework上的org.springframework.orm.jpa.ExtendedEntityManagerCreator $ ExtendedEntityManagerSynchronization.convertException(ExtendedEntityManagerCreator.java:501)org.springframework.orm.jpa.ExtendedEntityManagerCreator $ ExtendedEntityManagerSynchronization.afterCommit(ExtendedEntityManagerCreator.java:481)中的java:102) .transaction.support.TransactionSynchronizationUtils.invokeAfterCommit(TransactionSynchronizationUtils.java:133)org.springframework.transaction.support.TransactionSynchronizationUtils.triggerAfterCommit(TransactionSynchronizationUtils.java:121)org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerA fterCommit(AbstractPlatformTransactionManager.java:953)org.springframework上的org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:796)org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)位于org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java)的org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)中的.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393) :172)atg.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)at $ Proxy37.registerUser(Unknown Source)at com.missingwire.achieve.soa.endpoint.UserEndpoint.registerUser(UserEndpoint.java: 76)在sun.reflect.NativeMethodAccessor的sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) Impl.invoke(NativeMethodAccessorImpl.java:57)位于org.springframework.ws.server的java.lang.reflect.Method.invoke(Method.java:616)的sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) org.springframework.ws.server.endpoint.adapter.AbstractMethodEndpointAdapter上的org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter.invokeInternal(MarshallingMethodEndpointAdapter.java:140)中的.endpoint.MethodEndpoint.invoke(MethodEndpoint.java:132) .invoke(AbstractMethodEndpointAdapter.java:53)org.springframework.ws.server.MessageDispatcher.dispatch(MessageDispatcher.java:231)org.springframework.ws.server.MessageDispatcher.receive(MessageDispatcher.java:172)at org。 springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:88)at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:5 7)org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:221)org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:669)atg.springframework.web.servlet .FrameworkServlet.doPost(FrameworkServlet.java:585)位于org.apache的javax.servlet.http.HttpServlet.service(HttpServlet.java:637)的javax.servlet.http.HttpServlet.service(HttpServlet.java:717)。 catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)位于org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java: 233)org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)at org.apache.catalina.valves.ErrorReportValve .invoke(ErrorReportValve.java:102)atg.apache.catalina.core.StandardEngineValve。 在Org.apache上的org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)的org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)中调用(StandardEngineValve.java:109) .coyote.http11.Http11Protocol $ Http11ConnectionHandler.process(Http11Protocol.java:602)atg.apache.tomcat.util.net.JIoEndpoint $ Worker.run(JIoEndpoint.java:489)at java.lang.Thread.run(Thread .java:679)引起:javax.persistence.RollbackException:在org.springframework.orm.jpa.ExtendedEntityManagerCreator $ ExtendedEntityManagerSynchronization.afterCommit的org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:93)中提交事务时出错(ExtendedEntityManagerCreator.java:478)… 39更多引起:javax.persistence.PersistenceException:org.hibernate.exception.ConstraintViolationException:无法在org.hibernate.ejb.AbstractEntityManagerImpl.convert执行JDBC批量更新(AbstractEntityManagerImpl.java: 1235)在org.hibernate.ejb.AbstractEntityManage org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:81)中的rImpl.convert(AbstractEntityManagerImpl.java:1168)… 40更多引起:org.hibernate.exception.ConstraintViolationException:无法在以下位置执行JDBC批处理更新Org.hibernate.exvert.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)中的org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114)org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109)org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244) )org.hibernate.inseister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2395)org.hibernate.action.AbstractEntityPersister.insert(AbstractEntityPersister.java:2858)org.hibernate.action.EntityInsertAction.execute中的org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2395) EntityInsertAction.java:79) org.hibernate.engine.ActionQueue.exe执行(ActionQueue.java:267)org.hibernate.engine.ActionQueue。 )org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)org.hibernate.event.defaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)org.hibernate.impl.SessionImpl.flush的org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)在org.hibernate.ejb.TransactionImpl.commit的org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)上的SessionImpl.java:1206) (TransactionImpl.java:76)… 40更多引起:java.sql.BatchUpdateException:ORA-00001:违反了唯一约束(ACHIEVE.SYS_C0016488)

at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10070)atracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:213)org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) )org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)

您正在为扩展持久性上下文注入实体管理器。 这意味着持久化上下文的生命周期与事务的生命周期无关:它会保持打开状态,直到您明确地关闭它为止。

由于您遇到了RollbackException,因此持久性上下文处于脏的,不一致的状态,您唯一能做的就是立即关闭它。

如果持久性上下文是事务性上下文,则会自动关闭。 但是,由于您使用的是扩展上下文,因此您可以明确地将其关闭。

请务必阅读并理解Spring文档的以下部分:

@PersistenceContext注释具有可选的属性类型,默认为PersistenceContextType.TRANSACTION。 此默认值是您接收共享EntityManager代理所需的内容。 替代方案PersistenceContextType.EXTENDED是一个完全不同的事情:这导致了一个所谓的扩展EntityManager,它不是线程安全的,因此不能在并发访问的组件中使用,例如Spring管理的单例bean。 扩展的EntityManagers仅应用于有状态组件,例如,驻留在会话中,EntityManager的生命周期不依赖于当前事务,而是完全取决于应用程序。

添加:

 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) 

对于要排除transactionallity(例如查询)的方法,您将避免此问题。