在 Tomcat7 中使用 JDBC 连接池进行事务处理

Posted

技术标签:

【中文标题】在 Tomcat7 中使用 JDBC 连接池进行事务处理【英文标题】:Transaction handling with JDBC Connection Pooling in Tomcat7 【发布时间】:2015-06-22 12:07:18 【问题描述】:

我正在开发一个 JSF 应用程序,它通过 Tomcat 7 配置使用 JNDI 连接池连接到 DB2 数据库。我在管理事务时遇到问题,更具体地说,当共享连接的方法抛出异常时回滚。

以下代码建立一个连接并将其传递给所有其他被调用的方法。然后,此连接仅在方法的 finally 块中关闭。我的问题是,例如......如果在方法中的任何时候抛出异常,那么在此之前完成的任何工作都会被提交而不是回滚。我的印象是,在 finally 块中关闭连接时,如果在此连接的生命周期内引发任何异常,则不会提交,然后无论工作是否已提交或回滚,连接都会返回到池中.

public boolean updateSubCountry(SubCountryDTO dto,
        List<FeatureAliasDTO> aliases, List<FeatureCodeDTO> codes)
        throws ReferenceDataException 
    boolean success = true;
    Connection c = null;
    try 
        c = fDao.getConnection();
        success = fDao.updateSubCountry(c, dto, TEMP_USERNAME) && success;
        success = updateAliases(c, aliases, dto.getOdi(), TEMP_USERNAME,
                dto.getSubCountryId()) && success;
        for (FeatureCodeDTO codeDto : codes) 
            success = updateFeatureCode(c, codeDto, dto.getSubCountryId())
                    && success;
        
     finally 
        closeConnection(c, DEFAULT_CONNECTION_ERROR_MSG);
    
    return success;

我的 JNDI 配置如下(敏感信息已加星标):

<Resource name="jdbc/core" auth="Container" type="javax.sql.DataSource"
         url="****"
         driverClassName="com.ibm.db2.jcc.DB2Driver"
         username="****" password="****"
         maxActive="20" maxIdle="3" maxWait="10000"
         poolPreparedStatements="true"
         maxOpenPreparedStatements="100"
         validationQuery="SELECT 1 FROM SYSIBM.SYSDUMMY1" />

感谢任何帮助。

谢谢。

更新

我已尝试实施@Tiny 提出的建议。但是,当故意让 updateFeatureCode() 方法在数据库级别抛出异常时,在此之前的任何工作仍然没有回滚?

@Transactional (rollbackFor=Exception.class, ReferenceDataException.class)
    public boolean updateSubCountry(SubCountryDTO dto,
            List<FeatureAliasDTO> aliases, List<FeatureCodeDTO> codes)
            throws ReferenceDataException 
        boolean success = true;
        Connection c = null;
        try 
            c = fDao.getConnection();
            success = fDao.updateSubCountry(c, dto, TEMP_USERNAME) && success;
            success = updateAliases(c, aliases, dto.getOdi(), TEMP_USERNAME,
                    dto.getSubCountryId()) && success;
            for (FeatureCodeDTO codeDto : codes) 
                success = updateFeatureCode(c, codeDto, dto.getSubCountryId())
                        && success;
            
         finally 
            closeConnection(c, DEFAULT_CONNECTION_ERROR_MSG);
        
        return success;
    

【问题讨论】:

"我的印象是,在 finally 块中关闭连接时,如果在此连接的生命周期内抛出任何异常并将连接返回到池。“不。您需要将代码包装在事务单元周围。如果该单元内发生任何异常,事务单元内完成的工作将被还原/回滚。 好吧,最好的方法是什么?是否会将特定共享连接的自动提交设置为 false 并手动直接调用连接对象的回滚()和提交()? 应该很少需要将共享连接的自动提交设置为 false,但这取决于。然而,最好的方法是将此关键任务委托给您感兴趣的事务管理系统(声明性),例如 EJB (JTA) 或使用 org.springframework.transaction.annotation.Transactional 注释指定的 Spring 服务。 我设法通过手动将共享连接的自动提交设置为 false 来实现所需的行为,然后仅在没有引发异常时才提交。理想情况下,我想尝试使用前面提到的事务管理......我已经更新了上面的问题以显示我尝试过的内容。我在 pom.xml 中包含了 spring 依赖项,以将 spring api 引入我的项目。我在服务方法中包含了@transactional 标记,但是似乎没有任何变化并且事务不起作用?我是否需要在我的 JSF 项目中设置任何其他配置?谢谢。 【参考方案1】:

IBM JDBC 驱动程序在连接到 DB2 数据库时,默认为 autoCommit=true,这意味着在每个语句之后发出显式的 COMMIT。如果您希望自己控制事务,请根据需要禁用自动提交和提交或回滚。或者,按照@Tiny 的建议,使用事务管理器。

【讨论】:

我尝试使用事务管理器(请参阅更新后的帖子)。你能解释一下如何正确实现吗? 恐怕我对 J2EE 不太熟悉,无法在此提供很多帮助。

以上是关于在 Tomcat7 中使用 JDBC 连接池进行事务处理的主要内容,如果未能解决你的问题,请参考以下文章

Tomcat7 新的数据库连接池Tomcat jdbc pool介绍和配置

tomcat 7 jdbc连接池和jdbc4验证

如何记录 Tomcat 7 JDBC 连接池、连接创建

Tomcat 7 和 Oracle 连接池

tomcat7的数据库连接池tomcatjdbc的25个优势

Spring boot (11) tomcat jdbc连接池