我有一个@Transactional服务在oracle DB中执行持久化操作。如果我运行一个持久化程序来破坏一个唯一的违规,我会得到预期的rollbackException:ConstraintException。
问题是任何后续请求(即使没有违反唯一约束)都会持续存在同样的异常。
似乎JPA没有清除对象以保留其事务管理器?我甚至关闭?我需要一点解释。
回购:
@Repository
public class UserRepository {
@PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
public User findUserById(long id){
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> query = builder.createQuery(User.class);
Root<User> 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<User> query = builder.createQuery(User.class);
Root<User> 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:提交时出错 交易;嵌套异常是 javax.persistence.RollbackException:提交时出错 交易在 org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:311) 在 org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:102) 在 org.springframework.orm.jpa.ExtendedEntityManagerCreator $ ExtendedEntityManagerSynchronization.convertException(ExtendedEntityManagerCreator.java:501) 在 org.springframework.orm.jpa.ExtendedEntityManagerCreator $ ExtendedEntityManagerSynchronization.afterCommit(ExtendedEntityManagerCreator.java:481) 在 org.springframework.transaction.support.TransactionSynchronizationUtils.invokeAfterCommit(TransactionSynchronizationUtils.java:133) 在 org.springframework.transaction.support.TransactionSynchronizationUtils.triggerAfterCommit(TransactionSynchronizationUtils.java:121) 在 org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerAfterCommit(AbstractPlatformTransactionManager.java:953) 在 org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:796) 在 org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723) 在 org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393) 在 org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120) 在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 在 org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 在$ Proxy37.registerUser(未知来源)at com.missingwire.achieve.soa.endpoint.UserEndpoint.registerUser(UserEndpoint.java:76) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect.Method.invoke(Method.java:616)at org.springframework.ws.server.endpoint.MethodEndpoint.invoke(MethodEndpoint.java:132) 在 org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter.invokeInternal(MarshallingMethodEndpointAdapter.java:140) 在 org.springframework.ws.server.endpoint.adapter.AbstractMethodEndpointAdapter.invoke(AbstractMethodEndpointAdapter.java:53) 在 org.springframework.ws.server.MessageDispatcher.dispatch(MessageDispatcher.java:231) 在 org.springframework.ws.server.MessageDispatcher.receive(MessageDispatcher.java:172) 在 org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:88) 在 org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:57) 在 org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:221) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:669) 在 org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:585) 在javax.servlet.http.HttpServlet.service(HttpServlet.java:637)at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)at at org.apache.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) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) 在 org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859) 在 org.apache.coyote.http11.Http11Protocol $ Http11ConnectionHandler.process(Http11Protocol.java:602) 在 org.apache.tomcat.util.net.JIoEndpoint $ Worker.run(JIoEndpoint.java:489) 在java.lang.Thread.run(Thread.java:679)引起: javax.persistence.RollbackException:提交时出错 交易在 org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:93)at org.springframework.orm.jpa.ExtendedEntityManagerCreator $ ExtendedEntityManagerSynchronization.afterCommit(ExtendedEntityManagerCreator.java:478) ... 39更多引起:javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException:不能 执行JDBC批量更新 org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1235) 在 org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168) 在org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:81) ... 40更多引起: org.hibernate.exception.ConstraintViolationException:不能 执行JDBC批量更新 org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96) 在 org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) 在 org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275) 在 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.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2395) 在 org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2858) 在 org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79) 在org.hibernate.engine.ActionQueue.execute(ActionQueue.java:267)at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:259) 在 org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:178) 在 org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) 在 org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) 在org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)at at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375)at at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137) 在org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76) ... 40更多引起:java.sql.BatchUpdateException:ORA-00001: 违反了唯一约束(ACHIEVE.SYS_C0016488)
在 oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10070) 在 oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:213) 在 org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) 在 org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
答案 0 :(得分:7)
您正在为扩展的持久性上下文注入实体管理器。这意味着持久化上下文的生命周期与事务的生命周期无关:它会一直保持打开状态,直到您明确地关闭它为止。
由于您遇到RollbackException,持久化上下文处于脏的,不一致的状态,您唯一能做的就是立即关闭它。
如果持久性上下文是事务性上下文,则会自动关闭。但是,由于您使用了扩展的上下文,因此您可以明确地将其关闭。
请务必阅读并理解Spring文档的以下部分:
@PersistenceContext注释具有可选的属性类型, 默认为PersistenceContextType.TRANSACTION。默认为 你需要什么来接收共享的EntityManager代理。该 替代方案,PersistenceContextType.EXTENDED,是完全的 不同的事情:这会产生一个所谓的扩展EntityManager, 这不是线程安全的,因此不能同时使用 访问过的组件,例如Spring管理的单例bean。扩展 EntityManagers仅应用于有状态组件 例如,它驻留在会话中,具有生命周期 EntityManager与当前事务无关,而是与之相关 完全取决于应用程序。
答案 1 :(得分:0)
添加:
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
对于要排除transactionallity(例如查询)的方法,您将避免此问题。