【问题标题】:Connection pool exhausted in Spring Boot with JdbcTemplate使用 JdbcTemplate 在 Spring Boot 中耗尽连接池
【发布时间】:2017-04-27 15:21:42
【问题描述】:

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

它应该是这样工作的:

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

目前的运作方式:

  1. 请求很好。
  2. 来自 REST 端点的数据 - 正常。带有 DAO 的数据 -> 仅适用于带有两个 DAO 的前 50 个请求,之后就不行了。当其中一个 DAO 被禁用时,不会阻止任何连接。
  3. 50栋房子建好后,休息要很久才能完工,最后没有窗户。
  4. 使其无法用于更多请求,因为它们只会超时。

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

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

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

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

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

现在,我发现禁用一个或另一个 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"));
    }
}

【问题讨论】:

  • 不是一个答案,只是返回一个空列表来表示没有结果,而不是一个空的 Optional。您的捕获 (EmptyResultDataAccessException) 是不必要的:如果查询没有返回结果,Spring 只会返回一个空列表。
  • 感谢您的建议!
  • 你的WindowsRowMapper 在做什么。我也很难相信禁用一个或另一个不会出现问题(我怀疑它仍然存在,但需要更长的时间,大约 100 个请求)。
  • 我现在将进行更多测试并使用行映射器代码更新帖子。
  • 您的代码/配置中一定有一些东西没有正确返回到池的连接。您正在使用Atomikos,因此您正在使用 JTA,如果没有一个连接没有真正参与事务,请确保您的 JDBC 实际上支持 XA。​​

标签: java spring spring-boot dao jdbctemplate


【解决方案1】:

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

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

希望对你有帮助

【讨论】:

  • 我遇到了同样的错误。我正在使用带有 atomikos 的弹簧靴。我将 maxPoolSize 属性设置为 3(如 xaDS.setMaxPoolSize(3))并且有效,我没有收到错误,但是我不确定这是否是正确的修复或可能会破坏我的应用程序的解决方法。请提出建议。
  • 在最新的开源版本中修复了吗?
【解决方案2】:

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

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

Propagation.REQUIRES_NEW

到使用这些不同数据源的服务,所以它是:

@Service
@Transactional(propagation = Propagation.REQUIRES_NEW)

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

【讨论】:

  • 好建议 - 感谢分享!请记住,只有在您的服务没有更新方法时,这才是安全的。
猜你喜欢
  • 2017-07-10
  • 2018-11-28
  • 1970-01-01
  • 2015-06-04
  • 1970-01-01
  • 1970-01-01
  • 2022-07-24
  • 1970-01-01
相关资源
最近更新 更多