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

标签 java multithreading hibernate transactions c3p0

首先,我给出了一些数据点。
接下来将描述问题。

数据点:
[D1] HibernateAnnotationmanaged 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 文档说(link):

The most common pattern in a multi-user client/server application is session-per-request.



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

Pg will usually complete the same 10,000 transactions faster by doing them 5, 10 or 20 at a time than by doing them 500 at a time.



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


问题:
现在,如果我们使用带有注解的托管 bean 事务模式以及带有 hibernate 和每个请求 session 的连接池(假设只有 1 个连接)
还可以说代码类似于
@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 session .....不,我喜欢那种模式:)
2 Hibernate 提供 ConnectionRelease link可设置为 after_statement 的选项.
第一个 Hibernate C3P0 连接池提供程序不支持 after_statement。
其次,仅释放并重新获取连接将是开销。

最佳答案

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

1) 和 2) 都没有,也没有适合您需求的正确建议。

  • 您应该使用底层平台事务支持(例如 Java EE、Spring),而不是自己管理事务边界。
  • after_statement incurs some penalty ,而它仍然将事务绑定(bind)到连接。

  • 因此,可行的替代方案是:
  • 尽可能减少事务时间,以便您可以在每个数据库连接中执行大量事务。
  • 通过使用主从数据库复制和将只读事务路由到从属来增加可用的只读连接。
  • 关于java - 是否可以在单个 JDBC 连接上多路复用多个只读事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36920695/

    相关文章:

    java - 无法将模型对象添加到 "/"中的 jsp View ,但相同的方法正在调用/index

    java - AEM、Maven : Moving Service from one bundle to another bundle breaks the service wiring

    java - 向 ArrayList 添加一个新的类成员,自增标识符

    javascript - nodejs回调代码已同步

    java - StaleObjectStateException 或 OptimisticLockingException

    java - 我如何知道对象来自哪里,session缓存还是sessionFactory缓存

    java - 从 Sonarqube 导出编码规则列表

    java - Java Hashmap 中的 TREEIFY_THRESHOLD 是否有任何理由为 8?

    java - 出于线程调度目的,线程被禁用。这意味着什么?

    java - 不同事件线程之间的死锁