1

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

服务实现:

@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: Error while committing the transaction at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect. java:102) 在 org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerSynchronization.afterCommit(ExtendedEntityManagerCreator.java:481) 的 org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerSynchronization.convertException(ExtendedEntityManagerCreator.java:501) .transaction.support.TransactionSynchronizationUtils。

在 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)

4

2 回答 2

8

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

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

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

确保阅读并理解 Spring 文档的以下部分:

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

于 2012-11-30T15:26:32.283 回答
0

添加:

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) 

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

于 2013-09-10T13:50:11.887 回答