【问题标题】:Is it possible to multiplex multiple read-only transactions on a single JDBC Connection是否可以在单个 JDBC 连接上多路复用多个只读事务
【发布时间】:2016-08-23 13:45:52
【问题描述】:

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


数据点:
[D1]HibernateAnnotationmanaged objects 世界中,我看到了一个常见的模式,例如 p>

@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):

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

[D2] 此外,建议使用连接池库 C3P0 对数据库的连接进行池化,如 postgres 文档 (link) 所述:

Pg 通常一次完成 5、10 或 20 个事务比一次执行 500 个事务更快地完成相同的 10,000 个事务。

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


问题:
现在,如果我们使用带有注解的托管 bean 事务模式以及一个连接池(假设只有 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(...) 将执行只读查询,两个线程可以使用相同的连接并且不阻止线程执行查询。
在上述情况下,我们保持该连接空闲并保持线程等待。

主要问题
有没有一种方法可以让休眠让特定休眠事务是只读的,然后休眠可以重用已经获得的连接而不是要求来自连接池的新连接?


找到/建议的解决方案很少:(不令人信服)

1如果你很担心,不要使用注释使用事务,自己使用休眠会话.....不,我喜欢那种模式:)
2休眠提供ConnectionReleaselink可以设置为 after_statement 的选项。
FirstHibernate C3P0 连接池提供程序不支持 after_statement。
Second 这将是一个开销,只是释放和重新获取连接。

【问题讨论】:

  • 如果池中只有 1 个以上的连接,您不会有任何问题。这样做有什么意义?
  • 以上是为了解释...重点是在资源空闲时使用资源...上面的问题是仍然会在池中提供10个连接
  • 不,如果池中有足够的连接,则不会。我真的认为您正在寻找人为问题的解决方案。
  • 我认为当您知道您的服务器将在 3 秒的时间内收到 8000 个请求时会遇到问题......但重点是在资源空闲时使用资源跨度>

标签: java multithreading hibernate transactions c3p0


【解决方案1】:

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

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

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

因此,可行的替代方案是:

  1. 尽可能减少事务时间,以便您可以在每个数据库连接中执行大量事务。
  2. 通过使用主从数据库复制和将只读事务路由到从属设备来增加可用的只读连接。

【讨论】:

  • and the JDBC drivers are synchronous. 我怀疑... jdbc.postgresql.org/documentation/91/thread.htmlThe PostgreSQL™ JDBC driver is thread safe
  • 好吧,你发给我的链接的第 3 段怎么样。如果一个线程正在使用该连接,而另一个线程也想使用它,它将等到第一个线程完成。这听起来像多路复用吗?还是同步执行?
  • 是的,你是对的.. 但是如果我们阅读第 3 段的第二句,这意味着连接将在完成当前查询后立即移动到下一个操作,如果我们多路复用不同的只读查询,我们将不会在休眠忙于处理该查询的结果时让连接处于空闲状态。
猜你喜欢
  • 2017-10-05
  • 2012-01-08
  • 2016-11-19
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多