Hibernate 即使在提交和关闭后,交易仍处于打开状态
首先,我不知道这是否是解释我的问题的最佳标题,但现在我们开始:我有一个名为Hibernate 即使在提交和关闭后,交易仍处于打开状态,hibernate,postgresql,transactions,Hibernate,Postgresql,Transactions,首先,我不知道这是否是解释我的问题的最佳标题,但现在我们开始:我有一个名为Product的类,它在ProductPriceHistory上有一个@OneToOne映射 @Entity(name = "product") public class Product { @Id @SequenceGenerator(name="seq_product", sequenceName="seq_product", allocationSize=1 ) @GeneratedValue
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
来检索产品的当前价格。这可以正常工作几次,但在像10倍那样调用它之后,事务似乎仍然打开,因为我得到了这个异常(我想这是PostgreSQL中的特定异常):错误:致命:剩余的连接插槽保留给非复制超级用户连接
我尝试过这种方法:实例化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) {
(...)
}
}
公共类ProductPriceHistoryDaoImpl扩展了DefaultDaoImpl{
私有EntityManager em=HibernateManager.getEntityManager();
公共产品价格历史(){
super(ProductPriceHistory.class);
}
公共双getCurrentPriceByProductId(长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();
}
(...)
}
public抽象类DefaultDaoImpl{
私人实体管理者;
public void beginTx(){
em=HibernateManager.getEntityManager();
em.getTransaction().begin();
}
公共无效委员会(){
em.getTransaction().commit();
em.close();
}
(...)
}
我把它作为答案发布,因为我担心你得不到更好的答案。但请记住,我不是100%确定以下是否完全正确
Hibernate(包括其他JPA提供者)正在幕后管理一个抽象层,由创建的EntityManager使用。例如,在同一事务中可能有多个EntityManager。它至少有一部分是通过跟踪线程工作的
在您的例子中,您创建了一个新的EntityManager,同时可能在该线程中创建了另一个EntityManager,另外启动和提交事务并关闭EntityManager。我并不完全知道在这种情况下会发生什么,但你应该把它改成以下内容。
(我可能应该看看jpa规范对这种情况的说明,但我认为它没有直接涵盖)
对事务和线程的每个组合使用完全相同的EntityManager。这可能会使您自己管理变得复杂,这就是为什么越来越大的项目使用事务管理系统的原因。众所周知的例子是Spring和JavaEE。
如果你是wana,写下这个完整的管理者自己管理。有两个类可以方便地进行此操作。第一个是代理类,用于拦截调用并重定向到正确的实例。另一个是ThreadLocal,用于处理每线程状态 一个简单的想法-在
DefaultDaoImpl
方法中添加一些日志记录,以确认您的方法确实按照预期被调用
第二个观察结果是,您可能需要提供一些关于(jdbc?)驱动程序的信息:您使用的是池连接吗?你考虑过用一个吗?另外-为什么不修改您的价格DOA以获取一组项目-然后您可以为10个项目使用一个连接,而不是为每个项目使用10个连接