即使在提交和结束后交易仍然开放

时间:2015-05-07 00:53:52

标签: hibernate postgresql transactions

首先,我不知道这是否是解释我的问题的最佳标题,但我们走了:我有一个名为Product的班级,其中有一个{{ 1}} @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()来检索产品的当前价格。这样可以正常工作几次,但在调用它之后就像10x一样,看起来事务仍然是开放的,因为我得到了这个异常(我猜它是PostgreSQL特有的):Dao

我尝试过这种方法:实例化ERROR: FATAL: remaining connection slots are reserved for non-replication superuser connections,打开事务并将其关闭到调用ProductPriceHistoryDaoImpl productPriceHistoryDaoImpl的代码外面,然后通过参数传递它来调用查询,这很有效(插槽没有像第1种方法那样过载,但我不喜欢这种方法,因为我在getPrice()页面内使用getPrice(),我不能通过参数传递.jsp这些案例。

添加更多代码只是为了更清楚

ProductPriceHistoryDaoImpl

DefaultDaoImpl.java

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

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

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

2 个答案:

答案 0 :(得分:0)

我发布它作为答案,因为我担心你没有得到更好的答案。但请记住,如果以下内容完全正确,我不能100%确定。

Hibernate(包括其他JPA提供者)正在幕后管理一个抽象层,由创建的EntityManagers使用。例如,可以在同一事务中拥有多个EntityManager。至少它的一部分是通过跟踪线程来工作的。

在您的情况下,您创建一个新的EntityManager,同时可能还有另一个在该线程中创建的并且另外启动&amp;提交事务并关闭EntityManager。在这种情况下发生的事情并不完全为我所知,但您应该将其更改为以下内容。 (我可能应该查看jpa规范对该案例的说法,但我认为它没有直接涵盖)

对事务和线程的每个组合使用完全相同的EntityManager。这可能很难自行管理,这就是几乎所有大型项目都使用事务管理系统的原因。众所周知的例子是Spring和JavaEE。 如果你是wana写这个EntityManager自己管理。有两个类可以方便地执行此操作。第一个是Proxy类来拦截调用并重定向到正确的实例。另一个是ThreadLocal,用于处理每线程状态。

答案 1 :(得分:0)

快速思考一下 - 在DefaultDaoImpl方法中添加一些日志记录,以确认您的方法实际上是按预期调用的。

第二个观察结果是您可能需要提供有关您的(jdbc?)驱动程序的一些信息:您使用的是池化连接吗?你考虑过用过吗?另外 - 为什么不修改你的价格DOA来收集物品 - 然后你可以使用一个连接10个项目而不是每个项目10个连接。