【问题标题】:Transaction still open even after commiting and closing即使在提交和关闭后事务仍然打开
【发布时间】:2015-05-07 00:53:51
【问题描述】:

首先,我不知道这是否是解释我的问题的最佳标题,但我们开始吧:我有一个名为Product 的类,它在ProductPriceHistory 上有一个@OneToOne 映射。

@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() 的代码之外打开事务并关闭它,然后通过参数传递它来调用查询,这很完美(插槽没有被重载为在第一种方法中),但我不喜欢这种方法,因为我在.jsp 页面内使用getPrice(),并且在这些情况下我不能通过参数传递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();
    }

    (...)
}

【问题讨论】:

    标签: hibernate postgresql transactions


    【解决方案1】:

    我将其发布为答案,因为我担心您没有得到更好的答案。但请记住,我不能 100% 确定以下内容是否完全正确。

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

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

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-21
        • 2016-03-19
        • 1970-01-01
        • 1970-01-01
        • 2019-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多