Почему мы должны вручную сбрасывать () EntityManager в расширенном PersistenceContext? - PullRequest
9 голосов
/ 01 сентября 2011

В нашем приложении J2EE мы используем компонент EJB-3 с отслеживанием состояния, чтобы позволить переднему коду создавать, изменять и сохранять постоянные объекты (управляемые с помощью JPA-2).

Это выглядит примерно так:

@LocalBean
@Stateful
@TransactionAttribute(TransactionAttributeType.NEVER)
public class MyEntityController implements Serializable
{   
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    private MyEntity current;

    public void create()
    {
        this.current = new MyEntity();
        em.persist(this.current);
    }

    public void load(Long id)
    {
        this.current = em.find(MyEntity.class, id);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void save()
    {
        em.flush();
    }
}

Очень важно, чтобы избежать слишком ранних фиксаций, в транзакции используется только метод save(), поэтому, если мы вызываем create(), мы ничего не добавляем в базу данных.

Любопытно, что в методе save() мы должны вызвать em.flush(), чтобы действительно поразить базу данных. На самом деле, я попробовал и обнаружил, что мы также можем вызвать em.isOpen() или em.getFlushMode(), что угодно, что связано с em.

Я не понимаю этого вопроса. Поскольку save() находится в транзакции, я думал, что в конце метода транзакция будет зафиксирована, и поэтому диспетчер постоянных сущностей автоматически сбрасывается. Почему я должен вручную его промыть?

Спасибо, Xavier

Ответы [ 3 ]

7 голосов
/ 08 сентября 2011

Чтобы быть прямым и к металлу, не будет javax.transaction.Synchronization объектов, зарегистрированных для рассматриваемого EntityManager, пока вы на самом деле не используете это в транзакции.

Мы в app-server-land создадим один из этих объектов для выполнения flush() и зарегистрируем его с помощью javax.transaction.TransactionSynchronizationRegistry или javax.transaction.Transaction.Это невозможно сделать, если нет активной транзакции.

Это длинный и короткий путь.

Да, сервер приложений вполне может хранить список ресурсов, которые он предоставилbean-компонент и автоматически регистрирует их в каждой транзакции, в которой bean-компонент с состоянием может запускаться или участвовать. Недостатком этого является то, что вы полностью теряете возможность решать, какие операции будут выполняться в каких транзакциях.Возможно, у вас есть 2 или 3 разных транзакции для выполнения в разных единицах постоянства, и вы агрегируете работу в расширенном контексте постоянства для очень конкретной транзакции.Это действительно проблема проектирования, и сервер приложений должен оставлять такие решения для самого приложения.

Вы используете его в транзакции, и мы зарегистрируем его в транзакции.Это базовый контракт.

Примечание, в зависимости от того, как обрабатывается базовый EntityManager, любой постоянный вызов EntityManager может быть достаточным для полного сброса наконец сделки.Конечно, flush() является самым прямым и ясным, но persist() или даже find() может это сделать.

0 голосов
/ 13 июня 2014

Потому что нет способа узнать, "когда" клиент завершил сеанс (расширенная область).

0 голосов
/ 02 сентября 2011

Если вы используете расширенный контекст постоянства, все операции над управляемыми объектами, выполняемые внутри нетранзакционных методов, ставятся в очередь для записи в базу данных. Как только вы вызываете flush () в менеджере сущностей в контексте транзакции, все изменения в очереди записываются в базу данных. Другими словами, тот факт, что у вас есть транзакционный метод, не фиксирует изменения самостоятельно при выходе из метода (как в CMT), но фактически делает сброс менеджера объектов. Вы можете найти полное объяснение этого процесса здесь

...