Spring事务边界和DB连接保持
Posted
技术标签:
【中文标题】Spring事务边界和DB连接保持【英文标题】:Spring transaction boundary and DB connection holding 【发布时间】:2015-01-01 08:00:10 【问题描述】:我在 jpa 上使用 spring boot 和 hibernate 和 tomcat 连接池。你能帮我理解spring在事务中如何使用数据库连接吗?例如考虑以下场景:
-
我们有 2 个连接的数据库连接池。
Spring 启动事务,即调用带有 @Transactional 注释的方法。
此方法执行数据库更新
调用外部服务
当收到来自外部服务的响应时,它会更新 DB 并返回。
Spring 提交事务
假设外部服务(第 4 步)需要 1 分钟才能完成,那么 DB 池中有多少个 DB 连接可用?假设 spring 一直保持 DB 连接直到事务完成,在此期间收到的任何请求都只有 1 个 DB 连接可用,如果我们收到超过 1 个请求,他们将不得不等待 DB 连接。
请确认我的理解,如果正确,建议我如何在高交易量系统中处理这种情况。
谢谢
【问题讨论】:
【参考方案1】:首先你的理解是正确的。请参阅有关 declarative transaction management 的 spring 文档。
我猜你是在事务中进行外部服务调用,因为你希望在发生异常时回滚数据库更改。或者换句话说,您希望数据库更新反映外部服务调用的状态。
如果是这样,您就不能将其移出事务边界。在这种情况下,您应该增加连接池大小,或者您可以将长时间运行的事务委托给处理它们的专用服务器节点。这将保持例如一个“主”服务器节点,用于处理远离长时间运行事务的用户请求。
您应该考虑数据一致性。数据库更新是否真的必须与外部服务调用同步?外部服务调用能否移出事务边界?
【讨论】:
答案中的链接已损坏 @RegularUser 感谢您的提示。我更新了链接。 提取外部服务调用的逻辑是否可以通过@Transactional (propagation=Propogation.NOT_SUPPORTED) 修饰的方法解决事务长时间保持活跃的问题?当这个新方法被调用时,当前事务将被挂起(释放连接和其他获取的资源),当这个方法返回或抛出错误时,当前事务将再次恢复。所以你仍然可以在事务上下文本身中使用这个新方法调用(或外部服务)返回的结果。【参考方案2】:您可以根据您的要求指定连接池的初始大小和最大大小(取决于您的应用程序的性能)。
例如,
<bean id="springDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" >
<property name="url" value="jdbc:oracle:thin:@localhost:1521:SPRING_TEST" />
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="username" value="root" />
<property name="password" value="root" />
<property name="removeAbandoned" value="true"/>
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
</bean>
这将创建 20 个数据库连接,因为 initialSize 为 20,如果需要,最多可以创建 30 个数据库连接,因为 maxActive 为 30。您可以使用 Apache DBCP 库提供的不同属性自定义数据库连接池。上面的例子是使用 Oracle 11g 数据库创建连接池,我正在使用 oracle.jdbc.driver.OracleDriver 附带 ojdbc6.jar 或 ojdbc6_g.jar
【讨论】:
以上是关于Spring事务边界和DB连接保持的主要内容,如果未能解决你的问题,请参考以下文章
带有 Spring Boot 和事务边界的 graphql-spqr