Spring 使用 JdbcTemplate 启动时连接池耗尽

Connection pool exhausted in Spring Boot with JdbcTemplate

使用 Spring Boot 和 JdbcNamedTemplate 查询数据库时,我遇到了连接池耗尽的问题。

它应该是这样工作的:

  1. 收到来自外部的请求,其中包含一些关于房屋应该如何建造的参数。
  2. 根据收到的参数,使用一些 REST 端点和两个 DAO 来收集数据。
  3. 使用数据创建房屋对象并return它。
  4. 收到更多请求...

目前的运作方式:

  1. 请求很好。
  2. 来自 REST 端点的数据 - 好的。 Data with DAO -> OK only for first 50 requests with two DAOs, after that NOT OK.当禁用其中一个 DAO 时,不会阻止任何连接。
  3. 50栋房子建好后,休息要等很久才能完工,到头来没有windows
  4. 使其无法用于更多请求,因为它们只会超时。

当我调用端点超过 50 次(最大池大小)时出现此异常:

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

在我重新启动应用程序之前,它会保持这种状态。似乎我的 DAO 或配置有问题,但我一直无法弄清楚是什么,尽管搜索了一整天。如果有人能帮忙,我将不胜感激。

额外信息: 据我所知,没有抛出其他异常。 正确检索所有其他数据。 发送帮助。

更新: 我又做了一些实验: 这个应用程序使用了另一个我之前没有提到的 dao,因为我忘记了。 它的工作原理几乎相同,只是它连接到不同的数据库,所以它有一个单独的配置。它还利用 JdbcNamedTemplate 和 @Qualifier 用于 select 正确的。

现在,我发现禁用一个或另一个 DAO 将不再占用连接。那么问题来了:他们有什么不能和平共处的呢?

这就是道。

    @Component
    public class WindowsDao {

        private static final String PARAM_1 = "param";

        private final String SELECT_ALL = ""
                + " SELECT "
                + "   STUFF "
                + " FROM TABLE " 
                + " WHERE "
                + "     THING =:" + PARAM_1
                + " WITH UR";

        @Autowired
        private NamedParameterJdbcTemplate myTemplate;

        public Optional<List<BottomDealerText>> getWindows(
                final WindowsCode windowCode {

            final MapSqlParameterSource queryParameters = new MapSqlParameterSource()
                    .addValue(PARAM_1, windowCode.getValue())

            final Optional<List<Window>> windows;
            try {
                windows = Optional.of(myTemplate.query(
                        SELECT_ALL,
                        queryParameters,
                        new WindowsRowMapper()));
            }
            catch (final EmptyResultDataAccessException e) {
                LOG.warn("No results were found.");
                return Optional.empty();
            }
            return windows;
        }
    }

从该服务调用 DAO:

    @Service
    @Transactional
    public class WindowsService {

        @Autowired
        private WindowsDao windowsDao;

        public Optional<List<Stuff>> getWindows(
                final WindowCode windowCode) {
            final Optional<List<Window>> windows = windowsDao.getWindows(
                    windowCode;
            return windows;
        }
    }

从该服务中调用:

    @Service
    @Transactional
    public class AssembleHouseService { 
        // some things
        @Autowired
        private WindowsService windowsService;

        public House buildHouse(final SomeParams params) {
            // This service will fetch parts of the house
            HouseBuilder builder = House.builder();
            // call other services and then...
            builder.windows(windowsService.getWindows(args).orElse(/*something*/));
            //and then some more things...
        }
    }

这是我用来配置数据源的:

    myDb:
    driver: db2
    schema: STUFF
    unique-resource-name: STUFF
    database-name: STUFF1
    server-name: myServer
    port: 12312
    username: hello
    password: world
    driver-type: 4
    min-pool-size: 2
    max-pool-size: 50

行映射器:

public class WindowsRowMapper implements RowMapper<Window> {

    @Override
    public Windows mapRow(final ResultSet rs, final int rowNum)
            throws SQLException {
        return new BottomDealerText(
                re.getString("WSIZE"),
                rs.getString("DESCRIPTION"),
                rs.getString("COLOR"));
    }
}

如果您在同一个事务中有两个只读 DAO,那么您可能遇到了 Atomikos 开源版本中的一个已知错误,该错误仅在这种特定情况下才会出现。

它已在商业版中修复,但(尚未)在开源中修复。

希望对你有帮助

只是在这里发帖给那些寻找解决方法的人:

如果您不能更改为不同版本的 atomikos(或者只是放弃它),对我有用的是添加

Propagation.REQUIRES_NEW

到使用这些不同数据源的服务,因此它将是:

@Service
@Transactional(propagation = Propagation.REQUIRES_NEW)

似乎将这两个读取操作放入单独的事务中会使 atomikos 关闭事务并正确释放连接。