是否可以在单个JDBC连接上复用多个只读事务

时间:2016-04-28 16:42:15

标签: java multithreading hibernate transactions c3p0

首先,我提供的数据点很少 接下来将是所描述的问题。

数据点
[D1] Hibernate以及Annotationmanaged objects世界中,我看到的是像

这样的常见模式
@Transactional
public void createStuff(..){
// get entity manager and call persist and other operatation
}
@Transactional
public SomeDtoObject getStuff(..){
// get entity manager and call find and getter to polulate a object to return
}

在托管bean中,Hibernate事务在我们调用此方法时启动并提交。

Hibernate doc说(link):

  

多用户客户端/服务器应用程序中最常见的模式是每个请求的会话。

[D2] 还建议使用连接池库C3P0来汇集与数据库的连接,如postgres文档(link)中所述:

  

Pg通常会一次完成相同的10,000次交易,一次完成5次,10次或20次,而不是一次完成500次。

[D3] 还有JDBC
给定一个连接,我们可以一次运行一个事务,并在该事务中尽可能多地声明。 它取决于应用程序(C3P0),以确保执行两个不同事务方法的两个不同线程不应使用相同的连接,并且应该在调用另一个方法之前等待。

问题:
现在,如果我们使用带有hibernate和session-per-request的注释以及连接池(仅用1个连接)来使用托管bean事务模式 还要说代码就像

@Transactional
public SomeDtoObject getStuff(..){
// get entity manager and call find and getter to polulate a object to return
SomeEntity se = entityManager.find(someentity, primaryKey);
//create Dtos
// access someEntity to all over this method to create SomeDtoObject that we have to return.
// also may access some file on system to fetch some data is order to populate someDtoObject.
// overall let say the method take 150 milli second to do all its work
}

现在假设有两个不同的线程(T1T2)为getStuff(...)调用 T1将进入该方法并从连接池获取jdbc连接 当T2到达entityManager.find时,C3P0会检查没有连接,它将T2暂停,直到T1完成执行大约150毫秒。

理想情况下,假设getStuff(...)将执行只读查询,两个线程都可以使用相同的连接,并且不执行查询执行查询。 在上面的例子中,我们保持该连接空闲并保持线程等待。

主要问题
有没有办法说hibernate特定的hibernate事务是只读的,然后hibernate可以重用已经获得的连接而不是从连接池请求新的连接?

找到/建议的解决方案很少:(没有说服力)

1如果你非常担心,不要使用注释使用事务,请自己使用hibernate会话.....不,我喜欢那种模式:)
2 Hibernate提供了ConnectionRelease link选项,可以设置为after_statement
第一个 Hibernate C3P0连接池提供程序不支持after_statement 第二个它将是一个开销,只需释放并重新获取连接。

1 个答案:

答案 0 :(得分:0)

您不能将来自不同线程的事务多路复用到一个JDBC连接。即使JTA规范说这可能是可能的,但事实上,这并没有发生,并且JDBC驱动程序是同步的。

1)和2)以及适合您需求的正确建议。

  1. 您应该使用底层平台事务支持(例如Java EE,Spring),而不是自己管理事务边界。
  2. after_statement incurs some penalty,但它仍将事务绑定到连接。
  3. 因此,可行的替代方案是:

    1. 尽可能减少事务处理时间,以便每个数据库连接可以执行大量事务。
    2. 使用主从数据库复制增加可用的只读连接,并将只读事务路由到从属服务器。