spring 启动 atomikos 多数据源连接池耗尽 jdbc

spring boot atomikos multiple datasource connection pool exhausted plain jdbc

我有一个 Spring 引导应用程序,它使用 Atomikos 进行 JTA 托管事务。它使用多个数据源连接多个数据库。

第一个请求 returns 预期结果,但第二个请求失败并出现 'Pool exhausted' 异常。

我用普通 JDBC 和 JdbcTemplate 尝试过,但没有结果。是一样的。

这是我的 Spring 引导版本 1.5 的代码。8.RELEASE

@SpringBootApplication
@EnableAutoConfiguration(exclude = {
        DataSourceAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class, //if you are using Hibernate
        DataSourceTransactionManagerAutoConfiguration.class
})
@EnableTransactionManagement
public class App {

    public static void main(String[] arg) {
        SpringApplication.run(App.class, arg);
    }

}

第一种方法'index()'是普通的JDBC。第二个 'a()' 是 JdbcTemplate。

@RestController
@RequestMapping(value = "/demo")
@RequestScoped
public class Controller {

    @Autowired
    ApplicationContext ctx;

    @RequestMapping("")
    @org.springframework.transaction.annotation.Transactional(propagation = Propagation.REQUIRES_NEW)
    public String index() throws SQLException {
        DataSource imsdb = ctx.getBean("IMSDB", DataSource.class);
        Connection icon = imsdb.getConnection();

        DataSource sqldb = ctx.getBean("SQLDB", DataSource.class);
        Connection con = sqldb.getConnection();
        con.setAutoCommit(false);

        PreparedStatement stmt = con.prepareStatement("select current date from sysibm.sysdummy1");
        ParameterMetaData md = stmt.getParameterMetaData();
        md.getParameterCount();
        ResultSet rs = stmt.executeQuery();
        ResultSetMetaData rmd = rs.getMetaData();
        rmd.getColumnName(1);
        rs.next();
        Date date = rs.getDate(1);
        rs.close();
        stmt.close();

        PreparedStatement istmt = icon.prepareStatement("select current date from sysibm.sysdummy1");
        ParameterMetaData imd = istmt.getParameterMetaData();
        imd.getParameterCount();
        ResultSet irs = istmt.executeQuery();
        ResultSetMetaData irmd = irs.getMetaData();
        irmd.getColumnName(1);
        irs.next();
        Date idate = irs.getDate(1);
        irs.close();
        istmt.close();

        con.close();
        icon.close();

        return "dd";
    }

    @RequestMapping("/a")
    @org.springframework.transaction.annotation.Transactional(transactionManager = "transactionManager")
    public String a() throws SQLException {
        DataSource imsdb = ctx.getBean("IMSDB", DataSource.class);
        JdbcTemplate t1 = new JdbcTemplate(imsdb);

        DataSource sqldb = ctx.getBean("SQLDB", DataSource.class);
        JdbcTemplate t2 = new JdbcTemplate(sqldb);

        SqlRowSet rs = t1.queryForRowSet("select current date from sysibm.sysdummy1");
        rs.next();
        Date date = rs.getDate(1);
        SqlRowSet rs2 = t2.queryForRowSet("select current date from sysibm.sysdummy1");
        rs2.next();
        Date date2 = rs2.getDate(1);
        return date.toLocalDate().format(DateTimeFormatter.ISO_DATE);
    }

}

数据源配置:

@Configuration
@DependsOn("transactionManager")
public class DatabaseSqlConfig {

    @Primary
    @Bean(name = "SQLDB")
    @ConfigurationProperties(prefix = "spring.jta.atomikos.datasource.sql")
    public DataSource SQLDB() {
        return new AtomikosDataSourceBean();
    }

    @Bean(name = "IMSDB")
    @ConfigurationProperties(prefix = "spring.jta.atomikos.datasource.ims")
    public DataSource IMSDB() {
        return new AtomikosDataSourceBean();
    }

}

交易经理:

@Configuration
@ComponentScan
@EnableTransactionManagement
public class MainConfig {

    @Bean(name = "userTransaction")
    public UserTransaction userTransaction() throws Throwable {
        UserTransactionImp userTransactionImp = new UserTransactionImp();
        userTransactionImp.setTransactionTimeout(120);
        return userTransactionImp;
    }

    @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
    public TransactionManager atomikosTransactionManager() throws Throwable {
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        userTransactionManager.setForceShutdown(false);
        userTransactionManager.setTransactionTimeout(120);
        return userTransactionManager;
    }

    @Bean(name = "transactionManager")
    @DependsOn({ "userTransaction", "atomikosTransactionManager" })
    public JtaTransactionManager transactionManager() throws Throwable {
        UserTransaction userTransaction = userTransaction();
        TransactionManager atomikosTransactionManager = atomikosTransactionManager();
        return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
    }
}

应用程序 yml:

spring:
  jta:
    atomikos:
      datasource:
        sql:
          unique-resource-name: sql
          xa-data-source-class-name: com.ibm.db2.jcc.DB2XADataSource
          xa-properties:
            serverName: 10.141.86.14
            portNumber: 50000
            databaseName: XXX
            user: XXX
            password: db2
            driverType: 4
          initQuery: set current sqlid = 'LVM'
          testOnBorrow: true
          validationQuery: select 1 from sysibm.sysdummy1
          defaultAutoCommit: false
          max-pool-size: 1
          min-pool-size: 1
          reap-timeout: 10
        ims:
          unique-resource-name: ims
          xa-data-source-class-name: com.ibm.db2.jcc.DB2XADataSource
          xa-properties:
            serverName: 10.141.86.14
            portNumber: 50000
            databaseName: XXX
            user: XXX
            password: XXX
            driverType: 4
          initQuery: set current sqlid = 'XXX'
          testOnBorrow: true
          validationQuery: select 1 from sysibm.sysdummy1
          defaultAutoCommit: false
          max-pool-size: 1
          min-pool-size: 1
          reap-timeout: 10

和 pom 部门:

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>com.ibm.db2</groupId>
            <artifactId>db2jcc4</artifactId>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

这是日志:

第一个请求:

atomikos connection proxy for com.ibm.db2.jcc.am.sf@8ecb39e: calling createStatement...
2017-11-07 10:36:09.930 DEBUG 14473 --- [nio-8080-exec-1] c.atomikos.jdbc.AbstractDataSourceBean   : AtomikosDataSoureBean 'sql': getConnection()...
2017-11-07 10:36:09.930  INFO 14473 --- [nio-8080-exec-1] c.atomikos.jdbc.AbstractDataSourceBean   : AtomikosDataSoureBean 'sql': init...
2017-11-07 10:36:09.931 DEBUG 14473 --- [nio-8080-exec-1] c.a.icatch.imp.CompositeTransactionImp   : addParticipant ( XAResourceTransaction: 3132372E302E312E312E746D313531303034373336393836313030303031:3132372E302E312E312E746D32 ) for transaction 127.0.1.1.tm151004736986100001
2017-11-07 10:36:09.931 DEBUG 14473 --- [nio-8080-exec-1] c.a.datasource.xa.XAResourceTransaction  : XAResource.start ( 3132372E302E312E312E746D313531303034373336393836313030303031:3132372E302E312E312E746D32 , XAResource.TMNOFLAGS ) on resource sql represented by XAResource instance com.ibm.db2.jcc.t4.ec@7286dbb3
2017-11-07 10:36:09.931 DEBUG 14473 --- [nio-8080-exec-1] c.a.icatch.imp.CompositeTransactionImp   : registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@a9b32dad ) for transaction 127.0.1.1.tm151004736986100001
2017-11-07 10:36:09.931 DEBUG 14473 --- [nio-8080-exec-1] c.atomikos.jdbc.AtomikosConnectionProxy  : atomikos connection proxy for com.ibm.db2.jcc.am.sf@5e7e3715: calling createStatement...
2017-11-07 10:36:09.934 DEBUG 14473 --- [nio-8080-exec-1] c.atomikos.jdbc.AtomikosConnectionProxy  : atomikos connection proxy for com.ibm.db2.jcc.am.sf@8ecb39e: close()...
2017-11-07 10:36:09.935 DEBUG 14473 --- [nio-8080-exec-1] c.a.datasource.xa.XAResourceTransaction  : XAResource.end ( 3132372E302E312E312E746D313531303034373336393836313030303031:3132372E302E312E312E746D31 , XAResource.TMSUCCESS ) on resource ims represented by XAResource instance com.ibm.db2.jcc.t4.ec@44c74226
2017-11-07 10:36:09.935 DEBUG 14473 --- [nio-8080-exec-1] c.atomikos.jdbc.AtomikosConnectionProxy  : atomikos connection proxy for com.ibm.db2.jcc.am.sf@5e7e3715: close()...
2017-11-07 10:36:09.935 DEBUG 14473 --- [nio-8080-exec-1] c.a.datasource.xa.XAResourceTransaction  : XAResource.end ( 3132372E302E312E312E746D313531303034373336393836313030303031:3132372E302E312E312E746D32 , XAResource.TMSUCCESS ) on resource sql represented by XAResource instance com.ibm.db2.jcc.t4.ec@7286dbb3
2017-11-07 10:36:09.936 DEBUG 14473 --- [nio-8080-exec-1] c.a.icatch.imp.CompositeTransactionImp   : commit() done (by application) of transaction 127.0.1.1.tm151004736986100001
2017-11-07 10:36:09.938 DEBUG 14473 --- [nio-8080-exec-1] c.a.datasource.xa.XAResourceTransaction  : XAResource.prepare ( 3132372E302E312E312E746D313531303034373336393836313030303031:3132372E302E312E312E746D31 ) returning XAResource.XA_RDONLY on resource ims represented by XAResource instance com.ibm.db2.jcc.t4.ec@44c74226
2017-11-07 10:36:09.938 DEBUG 14473 --- [nio-8080-exec-1] c.a.datasource.xa.XAResourceTransaction  : XAResource.prepare ( 3132372E302E312E312E746D313531303034373336393836313030303031:3132372E302E312E312E746D32 ) returning XAResource.XA_RDONLY on resource sql represented by XAResource instance com.ibm.db2.jcc.t4.ec@7286dbb3

第二个请求直到出现异常:

2017-11-07 10:36:12.635 DEBUG 14473 --- [nio-8080-exec-2] c.a.i.i.CompositeTransactionManagerImp   : createCompositeTransaction ( 10000 ): created new ROOT transaction with id 127.0.1.1.tm151004737263500002
2017-11-07 10:36:12.635 DEBUG 14473 --- [nio-8080-exec-2] c.atomikos.jdbc.AbstractDataSourceBean   : AtomikosDataSoureBean 'ims': getConnection()...
2017-11-07 10:36:12.635  INFO 14473 --- [nio-8080-exec-2] c.atomikos.jdbc.AbstractDataSourceBean   : AtomikosDataSoureBean 'ims': init...
2017-11-07 10:36:22.693  WARN 14473 --- [     Atomikos:4] c.a.icatch.imp.ActiveStateHandler        : Timeout/setRollbackOnly of ACTIVE coordinator !
2017-11-07 10:36:42.637  WARN 14473 --- [nio-8080-exec-2] com.atomikos.jdbc.AtomikosSQLException   : Connection pool exhausted - try increasing 'maxPoolSize' and/or 'borrowConnectionTimeout' on the DataSourceBean.
2017-11-07 10:36:42.639 DEBUG 14473 --- [nio-8080-exec-2] c.a.icatch.imp.CompositeTransactionImp   : rollback() done of transaction 127.0.1.1.tm151004737263500002
2017-11-07 10:36:42.640 DEBUG 14473 --- [nio-8080-exec-2] c.a.icatch.imp.CompositeTransactionImp   : rollback() done of transaction 127.0.1.1.tm151004737263500002
2017-11-07 10:36:42.649 ERROR 14473 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is com.atomikos.jdbc.AtomikosSQLException: Connection pool exhausted - try increasing 'maxPoolSize' and/or 'borrowConnectionTimeout' on the DataSourceBean.] with root cause

com.atomikos.jdbc.AtomikosSQLException: Connection pool exhausted - try increasing 'maxPoolSize' and/or 'borrowConnectionTimeout' on the DataSourceBean.

我自己找到了解决方案。

Atomikos 事务管理器只是有一个错误 - 我切换到 Bitronix,现在一切正常。

这是 4.0.4 中的已知问题 - 将在 TransactionsEssentials 的 4.0.5 中修复。