Spring 使用 JdbcTemplate 启动时连接池耗尽
Connection pool exhausted in Spring Boot with JdbcTemplate
使用 Spring Boot 和 JdbcNamedTemplate 查询数据库时,我遇到了连接池耗尽的问题。
它应该是这样工作的:
- 收到来自外部的请求,其中包含一些关于房屋应该如何建造的参数。
- 根据收到的参数,使用一些 REST 端点和两个 DAO 来收集数据。
- 使用数据创建房屋对象并return它。
- 收到更多请求...
目前的运作方式:
- 请求很好。
- 来自 REST 端点的数据 - 好的。 Data with DAO -> OK only for first 50 requests with two DAOs, after that NOT OK.当禁用其中一个 DAO 时,不会阻止任何连接。
- 50栋房子建好后,休息要等很久才能完工,到头来没有windows
- 使其无法用于更多请求,因为它们只会超时。
当我调用端点超过 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 关闭事务并正确释放连接。
使用 Spring Boot 和 JdbcNamedTemplate 查询数据库时,我遇到了连接池耗尽的问题。
它应该是这样工作的:
- 收到来自外部的请求,其中包含一些关于房屋应该如何建造的参数。
- 根据收到的参数,使用一些 REST 端点和两个 DAO 来收集数据。
- 使用数据创建房屋对象并return它。
- 收到更多请求...
目前的运作方式:
- 请求很好。
- 来自 REST 端点的数据 - 好的。 Data with DAO -> OK only for first 50 requests with two DAOs, after that NOT OK.当禁用其中一个 DAO 时,不会阻止任何连接。
- 50栋房子建好后,休息要等很久才能完工,到头来没有windows
- 使其无法用于更多请求,因为它们只会超时。
当我调用端点超过 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 关闭事务并正确释放连接。