Guice впрыскивает EntityManager в многопоточное приложение

1

Я работаю над настольным приложением, использующим Java SE 7. Приложение использует несколько потоков, и в каждом потоке, который создается, DAO-класс вводится для получения доступа к моей базе данных. В качестве слоя persistence я использую EclipseLink и JPA. EntityManager вводится в мой класс DAO, используя инъекцию конструктора, и поскольку он не является потокобезопасным, я пошел на этот подход, используя такой прокси:

public PluginInstanceJpaController implements IPluginInstanceDao {

    private EntityManager em;

    @Injected
    public PluginInstanceJpaController(Provider<EntityManager> emp) {
        this.em = emp.get();
    }

    @Transactional 
    public void create(PluginInstance foo) throws Exception {
        em.persist(foo);
    }
}

Тем не менее, тот же экземпляр EntityManager вводится в каждый DAO. Для настройки этого я использовал JpaPersistModule, поскольку он предоставлен guice, и я уверен, что в моей настройке пока нет синглтонов.

Кто-нибудь знает, как сообщить об этом создателю нового экземпляра EntityManager при инъекции?

В другом подходе я пробовал настраиваемые поставщики для EntityManagerFactory и EntityManager и оставил JpaPersistModule вне моего бизнеса. Это привело к экземпляру EntityManager для DAO, однако @Transactional аннотированные методы не были перехвачены.

Буду признателен за любое решение этой проблемы. Спасибо, до сих пор!

--- EDIT ---

Классы DAO вводятся в Runnable, который их использует. Runnable также предоставляется через Поставщика. Моя конфигурация модуля выглядит примерно так:

public class RepositoryModule extends AbstractModule {

    @Override
    protected void configure() {

        // DAO bindings
        bind(IObjectStoreDao.class).to(ObjectStoreJpaController.class);
        bind(IPluginInstanceDao.class).to(PluginInstanceJpaController.class);
    }

    @Provides
    public PluginMonitor newMonitor(IPluginInstanceDao plugDao, IObjectStoreDao osDao) {
        PluginMonitor m = new PluginMonitor();
        m.setPluginInstanceDao(plugDao);
        m.setObjectStoreDao(osDao);
        return m;
    }
}

Здесь PluginMonitor - мой Runnable. Сам инжектор создается в моем основном потоке... возможно, это была проблема?

Теги:
jpa
guice

2 ответа

2

Это очень похожая проблема: Как Guice вводит синглтоны и неселекторы в несколько потоков

В ваш DAO это должно работать.

public PluginInstanceJpaController implements IPluginInstanceDao {

    private Provider<EntityManager> emProvider;

    @Injected
    public PluginInstanceJpaController(Provider<EntityManager> emp) {
        this.em = emp;
    }

    @Transactional 
    public void create(PluginInstance foo) throws Exception {
        em.get().persist(foo);
    }
}

Вы должны использовать Jfast Persistence Module или создать собственный поставщик EntityManager, который вернет новый EntityManager для каждого вызова get(), также он может быть реализована с помощью ThreadLocal, чтобы гарантировать, что EntityManager будет совместно использоваться в потоке.

0

Я не знаком с JPA, но надеюсь, что могу помочь: -)

Если вы посмотрите источник для EntityManagerProvider, вы увидите там ThreadLocal<EntityManager>. Поэтому по умолчанию каждый поток должен иметь свой собственный EntityManager. Это заставляет меня думать, что проблема в другом месте. Вы уверены, что ни один модуль не устанавливает EntityManager как одноэлементный? Как вы определяете, что все EntityManager являются одним и тем же объектом? Каждый DAO определенно находится в своей собственной теме? Можете ли вы предоставить подробную информацию о том, как FooDao настроен в вашем модуле и как новый FooDao предоставляется для каждого потока?

Кроме того, вы должны быть в порядке, чтобы написать свой конструктор как:

@Inject
public FooDao(EntityManager emp) {
    this.em = emp;
}

Guice поможет вам определить, что EntityManagerProvider предоставляет экземпляры EntityManager, и вызовет get() в экземпляре EntityManagerProvider, чтобы получить EntityManager для вашего конструктора.

  • 0
    Здравствуй! Я использовал отладчик eclipse, который давал мне один и тот же идентификатор отладки для любой ссылки EntityManager в каждом потоке, поэтому, если меня правильно информируют, это ссылается на один и тот же экземпляр. DAO вводятся провайдером, который предоставляет исполняемый объект (мой фактический поток выполнения). Поработав с этим часами, я решил убрать хитрость и идти своим путем. Однако, возможно, эта дискуссия может кому-то помочь.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню