我使用 Spring Boot、Apache DBCP 2、PostgreSQL 10 并通过
@Bean
public JdbcTemplate getJdbcTemplate() {
try {
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
Properties props = new Properties();
props.setProperty(PGProperty.USER.getName(), user);
props.setProperty(PGProperty.PASSWORD.getName(), password);
props.setProperty(PGProperty.APPLICATION_NAME.getName(), applicationName);
ConnectionFactory connectionFactory = new DriverManagerConnectionFactory("jdbc:postgresql://" + host + "/db",
props);
PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, null);
ObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolableConnectionFactory);
poolableConnectionFactory.setPool(connectionPool);
PoolingDataSource<PoolableConnection> dataSource = new PoolingDataSource<>(connectionPool);
return new JdbcTemplate(dataSource);
}
我通过以下方式访问数据库
@Autowired
private JdbcTemplate jdbc;
...
UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.randomUUID();
Array array = jdbc.getDataSource().getConnection().createArrayOf("UUID",
new Object[] { uuid1, uuid2 });
jdbc.query("SELECT * FROM my_table WHERE id = ANY (?)", //
ps -> ps.setArray(1, array), //
rs -> {
...
});
每次调用此选择查询时,都会创建与数据库的新会话。
如果我省略了准备好的语句并通过以下方式调用数据库
jdbc.query("SELECT * FROM my_table "
+ "WHERE id IN ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb')",
rs -> {
...
});
一切正常:不会创建到数据库的新会话。
如何以正确的方式使用预准备语句,而不会创建新会话?
您对jdbc.getDataSource().getConnection().createArrayOf
的用法是获取新连接,并且由于您从未关闭该获得的连接而泄漏连接。
如果要获取JdbcTemplate
使用的连接,则需要使用DataSourceUtils.getConnection
。
但是,您不需要创建该数组,JdbcTemplate
明确支持使用IN
列表,请参阅 Spring 文档中的传入 IN 子句的值列表。或者,考虑使用处理存储过程调用的复杂类型中所述SqlTypeValue
的方法。