微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JPA 和 JTA - 交易行为

如何解决JPA 和 JTA - 交易行为

我想知道以下内容

我有一个使用容器管理事务传递给 EJB 的 EntityManager。 在这个 EJB 中,我有一个 while 循环,我必须在其中为每次迭代创建一个新事务。 这是通过注入一个新的 ManagedBean 并在其方法上使用 @Transactional 注释 (REQUIRES_NEW) 在每次迭代时调用来完成的。

示例:

@Stateless
@LocalBean
@TransactionManagement(TransactionManagementType.CONTAINER)
public class EJBTask {

    @Inject
    private PersistenceUtility persistenceUtility;
    
    
    public process(EntityManager entityManagerEJB) { // The entity manager is passed from other classes (i.e. servlet)
        
        ...
        
        while(...) {
            
            persistenceUtility.executeInNewTransaction(new TransactionalTask(clientId,callerId,parametersReader) {
                
                public void onExecute(EntityManager entityManagerForNewTransaction) throws Throwable {
                    
                    // I'm using the entityManagerForNewTransaction for all the operations requiring nested transactions.
                    // But what happens if i try to use the entityManagerEJB instance? will it use the nested transaction or not?
                }
            });
        }
    }
}

import java.util.Set;

import javax.annotation.ManagedBean;
import javax.enterprise.context.Dependent;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import javax.transaction.Transactional.TxType;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import com.aurigaspa.basewebapp.util.Logger;

/**
 * <b>Description:</b><br>
 * A <code>PersistenceUtility</code> is a utility used to execute specific tasks inside a newly created transaction.<br>
 * This can be done by using {@link #executeInNewTransaction(TransactionalTask)} method.<br>
 * A <code>PersistenceUtility</code> makes use of {@link TransactionalTask} instances,which execute their specific logic by receiving a
 * specific {@link EntityManager} as input parameter in order to execute JPA operations on it.
 * 
 *
 * @see TransactionalTask
 */
@Dependent
@ManagedBean
public class PersistenceUtility {

    private static final Logger logger = Logger.getLogger(PersistenceUtility.class);

    @PersistenceContext(unitName = "scheduler")
    private EntityManager entityManager; //Do i really need to inject a new EntityManager?

    /**
     * <b>Description:</b><br>
     * Executes in a new transaction the provided {@link TransactionalTask}.<br>
     * The {@link TransactionalTask#onExecute(EntityManager)} method is invoked and a {@link TransactionRolledBackException} (containing the cause) is thrown
     * if exceptions occur during the processing of the {@link TransactionalTask},causing the transaction to be rollbacked. 
     *
     * @param transactionalTask The {@link TransactionalTask} instance to execute in the new transaction
     * @throws TransactionalException If errors occur during the processing of the {@link TransactionalTask}. The thrown exception contains the cause of the error.
     */
    @Transactional(value = TxType.REQUIRES_NEW,rollbackOn = Throwable.class)
    public void executeInNewTransaction(TransactionalTask transactionalTask) throws TransactionRolledBackException { //Could I pass the EntityManager of the EJBTask class? Does this lead me to the same result?

        Throwable exception = null;

        String loggingId = transactionalTask.getLoggingId();
        try {

            logger.debug(loggingId," - A new transaction has been created.");
            transactionalTask.onExecute(entityManager);
        } catch (InterruptedException e) {

            Thread.currentThread().interrupt();
            exception = e;
        } catch (ConstraintViolationException e) {

            Set<ConstraintViolation<?>> constraintViolation = e.getConstraintViolations();
            logger.error(loggingId," - ERROR: Exception during bean validation:");
            if (constraintViolation != null) {
                for (ConstraintViolation<?> violation : constraintViolation) {
                    /*
                     * loggo una linea di log di errore per ogni constraint violato
                     */
                    logger.error(loggingId," - ",String.format("%s=\"%s\" error: %s",violation.getPropertyPath(),violation.getInvalidValue(),violation.getMessage()));
                }
            }
            exception = e;
        } catch (Throwable e) {

            exception = e;

        } finally {

            if (exception != null || transactionalTask.mustRollBack()) {

                throw new TransactionRolledBackException("Transaction rolled back.",exception);
            } else {

                logger.debug(loggingId," - Transaction has been committed successfully.");
            }
        }
    }
}

在上面的例子中,一个新的 EntityManager 被注入。我想知道是否需要注入一个新的 EntityManager 或者我可以重用 EJB 中已经存在的 EntityManager,它调用 executeInNewTransaction 方法(可能通过显式传递它的 entityManager)。 请注意,EntityManager 实例指的是同一个持久化单元。

我期望重用相同的 EntityManager 实例,它一次只获取一个事务,并自动适用于“最内部”的事务上下文。我对吗?还是我真的应该使用两个不同的 EntityManager 实例?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。