2016-06-16 3 views
0

Я использовал этот учебник их так же, как в моем приложении: http://www.benmccann.com/hibernate-with-jpa-annotations-and-guice/Джерси, Guice и Hibernate - EntityManager потокобезопасность

Мое приложение является JAX-RS веб-сервис, который будет получать много одновременных запросов и вносить обновления в базу данных.

реализация GenericDAOImpl.java:

public class GenericDAOImpl<T> implements GenericDAO<T> { 

    @Inject 
    protected EntityManager entityManager; 

    private Class<T> type; 

    public GenericDAOImpl(){} 

    public GenericDAOImpl(Class<T> type) { 
     this.type = type; 
    } 

    @Override 
    public void save(T entity) { 
     entityManager.getTransaction().begin(); 
     entityManager.persist(entity); 
     entityManager.getTransaction().commit(); 
    } 

}

Если 2 параллельных потоков пытаются сохранить сущность, я получаю

java.lang.IllegalStateException: Transaction already active 

Saving работает хорошо, если я комментирую сделку.

Я пытался использовать

@Inject 
protected Provider<EntityManager> entityManagerProvider; 

или

@Inject 
protected EntityManagerFactory entityManagerProvider; 

и для каждого запроса:

EntityManager entityManager = entityManagerProvider.get() 

Но я получаю:

org.hibernate.PersistentObjectException: detached entity passed to persist 

Каков правильный способ внедрения Guice + Hibernate EntityManager для инъекций/потокобезопасного общего класса DAO?

UPDATE

Андрей Рейнер комментарий от http://www.benmccann.com/hibernate-with-jpa-annotations-and-guice/

«Логика не совсем готовый к производству - по крайней мере, если он используется в веб-приложение

Зимует пул соединений является очень простой. и не готово к производству - рекомендуется использовать пул источников данных, такой как c3p0.

EntityManager должен не следует использовать повторно - он предназначен для создания за транзакцию/запрос. Существует хорошая вероятность загрязнения последующих запросов.

Существует также откат транзакций, если что-то пойдет не так.

Интересный подход - но это было бы гораздо безопаснее для WebApps использовать Guices собственный Упорство модуль расширения для управления жизненным циклом экземпляров EntityMananger и сделок «

ответ

0

Проблема заключалась в том, что моя конечная точка была аннотацию @Singleton так повторно один и тот же EntityManager при одновременных вызовов. После удаления @Singleton во время одновременных вызовов используются разные объекты EntityManager. Если последующие вызовы конечной точки, возможно, будет использоваться предыдущий/старый EntityManager.

Очень упрощенный пример:

@Path("/v1/items") 
public class ItemsService { 

    @Inject 
    private EntityManager entityManager; 

    @POST 
    @Path("/{id}") 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    public void saveItem(){ 
     entityManager.getTransaction().begin(); 
     entityManager.persist(new Item()); 
     entityManager.getTransaction().commit(); 
    } 
} 
0

Прежде всего, какого рода EntityManager вы используете.? Глядя на ваш код я suposse такого рода является применение управляемого EntityManager было бы важно для вас, чтобы понять различные типы EntityManager

Пожалуйста, см.. http://docs.oracle.com/javaee/6/tutorial/doc/bnbqw.html

Основываясь на этом, вы должны создать EntityManagerFactory объект а затем создать объект EntityManager.

Basic Пример:

private static EntityManagerFactory emf; 
EntityManager em = null; 

public static EntityManagerFactory getEmf(){ 
    if(emf == null){ 
     emf = Persistence.createEntityManagerFactory("nameOfYourPersistenceUnit"); 
    } 
    return emf; 
} 


em = getEmf().createEntityManager(); 
em.getTransaction().begin(); 
em.persist(entity); 
em.getTransaction().commit(); 
em.close(); 
+0

У меня есть метод @Provides общественного EntityManager provideEntityManager (EntityManagerFactory EntityManagerFactory), которые «используют хранилище ThreadLocal здесь, чтобы иметь один менеджер сущностей в потоке». как упоминалось в http://www.benmccann.com/hibernate-with-jpa-annotations-and-guice/ – Justas

0

Если это говорит о том, что транзакция уже открыта, это означает, что он был открыт другим процессом и не закрыт ...

Я предлагаю использовать @Transactionl вместо:

em.getTransaction().begin(); 

и

em.getTransaction().commit(); 
em.close(); 

Это будет управлять вещи для вас ...

так что для вас это будет так:

@Transactionl 
@POST 
@Path("/{id}") 
@Consumes(MediaType.APPLICATION_JSON) 
@Produces(MediaType.APPLICATION_JSON) 
public void saveItem(){ 
    entityManager.persist(new Item()); 
} 

надеюсь, что это поможет

Смежные вопросы