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事务注解

带有 Spring Boot 和事务边界的 graphql-spqr

如何使用 JOOQ 和 Spring-boot 2.0 进行手动事务管理?

Spring中的事务与数据库中的锁关系

Spring 事务传播特性

Spring事务隔离级别和传播特性