事务已启动但未在数据库测试连接查询中结束

时间:2014-08-05 15:01:35

标签: java spring postgresql groovy bonecp

最近在我们的应用程序中发现了一个错误,导致操作时间与实际时间不同(我们使用的是current_timestamp()PostgreSQL函数,而不是从代码中传递时间)。我们已经对它进行了调查,发现问题不得不与一些已经开始但从未结束的交易有关。

该应用程序使用Spring DataSourceTransactionManager,它可以完美地完成工作(每个事务操作都按预期结束)。现在,问题似乎来自我们的连接池lib(BoneCP)。我们已配置SELECT 1查询以检查数据库连接。 PostgreSQL日志中实际显示的内容如下:

LOG: execute S_1: BEGIN
LOG: execute <unnamed>: SELECT 1
LOG: execute S_1: BEGIN
LOG: execute <unnamed>: SELECT 1

没有COMMIT跟随任何连接测试语句(进一步的日志显示在SELECT 1之前没有更多BEGIN命令,但我想这是因为当一个已经激活时,该连接无法启动新事务。

我想知道是不是有些错误或可能出错?

这是servlet-context配置文件(仅发布相关部分):

<bean id="ds" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
    <property name="idleConnectionTestPeriodInMinutes" value="5"/>
    <property name="idleMaxAgeInMinutes" value="30"/>
    <property name="lazyInit" value="true"/>
    <property name="maxConnectionsPerPartition" value="95"/>
    <property name="minConnectionsPerPartition" value="1"/>
    <property name="partitionCount" value="3"/>
    <property name="acquireIncrement" value="5"/>
    <property name="statementsCacheSize" value="100"/>
    <property name="releaseHelperThreads" value="3"/>
    <property name="defaultAutoCommit" value="false"/>
    <property name="connectionTestStatement" value="SELECT 1;"/>
</bean>

<bean id="sql" class="groovy.sql.Sql">
    <constructor-arg ref="dsProxy"/>
</bean>

<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>

<bean id="dsProxy" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
    <constructor-arg ref="fooDSProxy"/>
</bean>

<bean id="fooDSProxy" class="org.something.Foo" factory-method="createProxy">
    <constructor-arg ref="ds"/>
</bean>

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dsProxy"/>
</bean>

org.something.Foo没有什么特别之处,用于记录目的。

任何帮助表示感谢。

1 个答案:

答案 0 :(得分:0)

问题可能是由于数据库连接上的自动提交设置。

正如名称所暗示的那样,autocommit会自动将每个SQL语句包装在自己的事务中,并在语句结束时隐式提交该事务。对于很多生产场景,自动提交没有意义;您通常希望将一批SQL操作组合到一个事务中,然后提交或回滚工作单元。

您的数据库连接池设置显式关闭了连接上的自动提交,因此我建议您在没有显式提交的事务中执行您的SELECT 1连接测试语句。这可以解释为什么你看到BEGIN语句然后没有提交。解决此问题的方法是更新连接测试语句以包括显式事务划分,例如在语句中添加BEGINCOMMIT

就未提交的连接实际发生的情况而言,这将取决于实际的数据库实现本身。可能值得一读的是什么 PostgreSQL会在这里做。

Hibernate文档提供了pretty good对依赖自动提交的情况的解释。绝对值得一读。