1

Oracle DB への永続化アクションを実行する @Transactional サービスがあります。固有の違反を破る永続化を実行すると、予想される 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.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:311) at 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.

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 などの同時アクセス コンポーネントで使用してはなりません。拡張された EntityManagers は、セッションに常駐するステートフル コンポーネントでのみ使用することを想定しており、EntityManager のライフサイクルは現在のトランザクションに関連付けられておらず、完全にアプリケーション次第です。

于 2012-11-30T15:26:32.283 に答える