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

时间:2012-11-30 04:20:01

标签: java exception jpa transactions

我有一个@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)

2 个答案:

答案 0 :(得分:7)

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

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

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

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

  

@PersistenceContext注释具有可选的属性类型,   默认为PersistenceContextType.TRANSACTION。默认为   你需要什么来接收共享的EntityManager代理。该   替代方案,PersistenceContextType.EXTENDED,是完全的   不同的事情:这会产生一个所谓的扩展EntityManager,   这不是线程安全的,因此不能同时使用   访问过的组件,例如Spring管理的单例bean。扩展   EntityManagers仅应用于有状态组件   例如,它驻留在会话中,具有生命周期   EntityManager与当前事务无关,而是与之相关   完全取决于应用程序。

答案 1 :(得分:0)

添加:

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) 

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