2015-05-07 2 views
0

Прежде всего, я не знаю, является ли это лучшим заголовком, чтобы объяснить, в чем моя проблема, но здесь мы идем: у меня есть класс под названием Product, который имеет @OneToOne отображение на ProductPriceHistory ,Сделка по-прежнему открыта даже после совершения и закрытия

@Entity(name = "product") 
public class Product { 
    @Id 
    @SequenceGenerator(name="seq_product", sequenceName="seq_product", allocationSize=1) 
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq_product") 
    private long id; 

    @Column(name="description", length=150) 
    private String description; 

    @OneToOne 
    private ProductPriceHistory price; 
    (...) 

    public double getPrice() { 
     double price = 0.0; 

     ProductPriceHistoryDaoImpl productPriceHistoryDaoImpl = new ProductPriceHistoryDaoImpl(); 

     try { 
      productPriceHistoryDaoImpl.beginTx(); 
      price = productPriceHistoryDaoImpl.getCurrentPriceByProductId(this.id); 
      productPriceHistoryDaoImpl.commitTx(); 
     } catch(Exception e) { 
      (...) 
     } 

     return price; 
    } 
} 

Как вы можете видеть на моем getPrice() методе, я звоню другой Dao, чтобы получить текущую цену на продукт. Это работает нормально несколько раз, но после вызова его как 10x, похоже, что транзакции все еще открыты, потому что я получаю это исключение (я предполагаю, что это специфично для PostgreSQL): ERROR: FATAL: remaining connection slots are reserved for non-replication superuser connections.

Я пробовал этот подход: создавал экземпляр ProductPriceHistoryDaoImpl productPriceHistoryDaoImpl, открывая транзакцию и закрывая ее ВНЕ кода, который вызывает getPrice(), и просто передайте его по параметру, чтобы вызвать запрос, и это работает отлично (слоты не перегружены, как в 1-м подход), но мне не нравится этот подход, потому что я использую getPrice() внутри .jsp страниц, и я не могу передать ProductPriceHistoryDaoImpl параметром в этих случаях.

Добавление немного больше кода просто понятнее

public class ProductPriceHistoryDaoImpl extends DefaultDaoImpl<ProductPriceHistory>{ 
    private EntityManager em = HibernateManager.getEntityManager(); 

    public ProductPriceHistory() { 
     super(ProductPriceHistory.class); 
    } 

    public double getCurrentPriceByProductId(long productId) { 
     (...) 
    } 
} 

DefaultDaoImpl.java

public abstract class DefaultDaoImpl<T> { 
    private EntityManager em; 

    public void beginTx() { 
     em = HibernateManager.getEntityManager(); 
     em.getTransaction().begin(); 
    } 

    public void commitTx() { 
     em.getTransaction().commit(); 
     em.close(); 
    } 

    (...) 
} 

ответ

0

я его в ответ, потому что я боюсь, что вы не получите лучше ответ. Но имейте в виду, что я не уверен на 100%, если следующее полностью верно.

Hibernate (включая других поставщиков JPA) управляет за кулисами уровнем абстракции, используемым создаваемыми EntityManagers. Например, в одной транзакции возможно иметь более одного EntityManager. По крайней мере части его работают через отслеживание потоков.

В вашем случае вы создаете новый EntityManager, возможно, еще один созданный в этом потоке и дополнительно начинающий & совершая транзакцию и закрывая EntityManager. То, что происходит в этом случае, точно не полностью известно мне, но вы должны изменить его на следующее. (я могу проверить, что говорит спецификация jpa для этого случая, но я предполагаю, что он не покрыт напрямую)

Используйте точно такой же EntityManager для каждой комбинации транзакций и потоков. Это может быть сложным для управления самостоятельно, поэтому причина, почему почти когда-либо более крупный проект использует систему управления транзакциями. Известными примерами являются Spring и JavaEE. Если youre wana записывает это EntityManager самостоятельно. Для этого есть два класса. Первый - это класс Proxy для перехвата вызовов и перенаправления на правильный экземпляр. Другой - ThreadLocal для обработки состояния каждого потока.

0

Быстрое размышление - добавьте некоторые способы регистрации в свои методы DefaultDaoImpl, чтобы подтвердить, что ваши методы на самом деле вызываются, как вы ожидаете.

Второе замечание состоит в том, что вам, вероятно, необходимо предоставить некоторую информацию о вашем драйвере (jdbc?): Используете ли вы объединенное соединение? Рассматривали ли вы его использование? Кроме того, почему бы не изменить свою цену DOA, чтобы взять коллекцию предметов, - тогда вы можете использовать одно соединение для 10 элементов вместо 10 подключений по одному элементу.

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