Распространение EntityManager в EJB 3 - PullRequest
2 голосов
/ 10 июля 2020

Рассмотрим следующий сценарий:


@Stateless
public class A{

        
    @PersistenceContext
    private EntityManager em;

    @EJB
    B b;

    @EJB
    C c;

    public void doSomeWork(){
    b.doSomeWork();
    c.doSomeWork();
    em.persist(someStuff);
    }
    
}
@Stateless
public class B{
        
    @PersistenceContext
    private EntityManager em;

    public void doSomeWork(){
    //Do stuff
    em.persist(stuff)
    }

    
}
@Stateless
public class C{
        
    @PersistenceContext
    private EntityManager em;

    public void doSomeWork(){
    //Do stuff
    em.persist(stuff)
    }

    
}

В этом сценарии я использую три разных EntityManager для одной и той же транзакции (запущено методом doSomeWork() из class A

Теперь та же транзакция, но только с одним EntityManager:

@Stateless
public class A{

        
    @PersistenceContext
    private EntityManager em;

    @EJB
    B b;

    @EJB
    C c;

    public void doSomeWork(){
    b.setTheEntityManager(em);
    b.doSomeWork();
    c.setTheEntityManager(em);
    c.doSomeWork();
    em.persist(someStuff);
    }
    
}
@Stateless
public class B{
        
    private EntityManager em;

    public void setTheEntityManager(EntityManager em){
    this.em = em;
    }

    public void doSomeWork(){
    //Do stuff
    em.persist(stuff)
    }

    
}
@Stateless
public class C{
        
    private EntityManager em;

    public void setTheEntityManager(EntityManager em){
    this.em = em;
    }

    public void doSomeWork(){
    //Do stuff
    em.persist(stuff)
    }
}

Я читал о жизненном цикле EntityManager, но я просто не могу понять, есть ли какие-либо преимущества (с точки зрения производительности, подключений к базе данных, ..) в Второй сценарий. Мой первый ответ - да, потому что существует только один EntityManager, но, с другой стороны, я не вижу никаких примеров кода, использующих этот подход (передача EntityManager из EJB в EJB). Кроме того, в Oracle Документах говорится: « Благодаря автоматическому распространению контекста постоянства компоненты приложения не должны передавать друг другу ссылки на экземпляры EntityManager, чтобы вносить изменения в рамках одной транзакции. Контейнер Java EE управляет жизненным циклом диспетчеров объектов, управляемых контейнером. "

1 Ответ

0 голосов
/ 10 июля 2020

Все, что вы @Inject или @Resource из контейнера, не должно никогда передавать куда-то еще. Это верный способ создать утечку памяти и / или неопределенное поведение. Также нет никаких преимуществ в использовании второго сценария, так как контейнер автоматически вводит правильный EntityManager каждый раз:)

Короче говоря, никогда не выполняйте второй сценарий, всегда выполняйте первый сценарий. Контейнер фактически вводит прокси-сервер, который направляет вас к правильному (то же самое в вашем случае, поскольку вы не вышли из границы транзакции) менеджеру сущностей.

Что происходит, так это то, что вызов a.doSomeWork() подразумевает TransactionAttribute.Required. Если транзакция еще не была запущена, контейнер запускает ее за вас. Последующие вызовы B и C теперь участвуют в этой транзакции. Когда вы выходите из a.doSomeWork(), предполагая, что транзакция началась именно там, транзакция фиксируется. Все, что делается A, B и C, происходит в одной транзакции.

...