JDBC模板运行缓慢
JDBC模板运行缓慢
我在使用JDBCTemplate从数据库中获取一行数据时遇到了性能问题。当我在PLSQL中运行SQL时,可以在3毫秒内获得结果,但是在代码中相同的查询需要大约200毫秒。我认为这是因为在运行查询之前,会创建一个连接,而我在连接上浪费了太多时间。我猜我需要一个连接池或其他的解决方案。
在编写代码之前,我想讨论一下我的Spring Boot项目的流程。客户端调用我的端点,在这个调用中,我使用了多个来自多个表的查询。由于每个查询都会创建一个新的连接,所以所有的查询都运行得很慢。
数据库配置类:
@Configuration
public class DatabaseConfig {
@Autowired
private Environment env;
@Bean(name = "fraudDb")
public DataSource masterDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("driver-class-name"));
dataSource.setUrl(env.getProperty("fraud.url"));
dataSource.setUsername(env.getProperty("fraud.username"));
dataSource.setPassword(env.getProperty("fraud.password"));
return dataSource;
}
@Bean(name = "ndvliveDb")
public DataSource secondDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("driver-class-name"));
dataSource.setUrl(env.getProperty("ndvlive.url"));
dataSource.setUsername(env.getProperty("ndvlive.username"));
dataSource.setPassword(env.getProperty("ndvlive.password"));
return dataSource;
}
@Bean(name = "fraudJdbcTemplate")
@Autowired
public JdbcTemplate masterJdbcTemplate(@Qualifier("fraudDb") DataSource fraudDb) {
return new JdbcTemplate(fraudDb);
}
@Bean(name = "ndvliveJdbcTemplate")
@Autowired
public JdbcTemplate secondaryJdbcTemplate(@Qualifier("ndvliveDb") DataSource ndvliveDb) {
return new JdbcTemplate(ndvliveDb);
}
}
RestController中的查询:
private RbtranServiceInputModel services(FraudActionsRestRequest fraudActionsRestRequest) {
Long start = System.nanoTime();
String debitSegmentId = ndvliveCustomerInfoService.getSBUCode(Integer.parseInt(cifNoSender));
Long end = System.nanoTime();
System.out.println("debitSegmentId " + (end - start) / 1e6);
// 其他查询...
}
这个函数最多需要2秒钟。
DAO:
public interface CustomerInformationTempDao {
String getSbuCodeByClientNo(Integer clientNo);
}
DAOImpl:
@Repository
public class CustomerInformationTempDaoImpl implements CustomerInformationTempDao {
@Autowired
@Qualifier("ndvliveJdbcTemplate")
private JdbcTemplate ndvliveJdbcTemplate;
public String getSbuCodeByClientNo(Integer clientNo) {
String query = "SELECT * FROM mytable WHERE client_no=" + clientNo;
try {
return ndvliveJdbcTemplate.queryForObject(query, (resultSet, i) -> resultSet.getString("SBU_CODE"));
} catch (EmptyResultDataAccessException e) {
return null;
}
}
}
解决方案:更改DriverManagerDataSource
@Configuration
public class DatabaseConfig {
@Autowired
private Environment env;
@Autowired
private DataSourceProperties dataSourceProperties;
@Bean(name = "fraudDb")
public DataSource masterDataSource() {
DataSourceBuilder factory = DataSourceBuilder
.create(this.dataSourceProperties.getClassLoader())
.driverClassName(env.getProperty("driver-class-name"))
.url(env.getProperty("fraud.url"))
.username(env.getProperty("fraud.username"))
.password(env.getProperty("fraud.password"));
return factory.build();
}
@Bean(name = "ndvliveDb")
public DataSource secondDataSource() {
DataSourceBuilder factory = DataSourceBuilder
.create(this.dataSourceProperties.getClassLoader())
.driverClassName(env.getProperty("driver-class-name"))
.url(env.getProperty("ndvlive.url"))
.username(env.getProperty("ndvlive.username"))
.password(env.getProperty("ndvlive.password"));
return factory.build();
}
@Bean(name = "fraudJdbcTemplate")
@Autowired
public JdbcTemplate masterJdbcTemplate(@Qualifier("fraudDb") DataSource fraudDb) {
return new JdbcTemplate(fraudDb);
}
@Bean(name = "ndvliveJdbcTemplate")
@Autowired
public JdbcTemplate secondaryJdbcTemplate(@Qualifier("ndvliveDb") DataSource ndvliveDb) {
return new JdbcTemplate(ndvliveDb);
}
}
JDBC Template Works Slow(JDBC模板工作缓慢)问题的原因可能是以下几点:
1. 使用DriverManagerDataSource
代替定义一个具有固定连接数的连接池。简化起见,可以使用SingleConnectionDataSource
,它不会执行任何借用连接验证操作。虽然这不是一个适用于生产环境的设置,但在测试中会减少一些不必要的移动部件。
2. 不要使用SELECT *
,而是只指定需要的列。解析*
在JDBC和命令行客户端之间可能会有所不同,最好去掉这个不确定因素。
3. 使用带有client_no = ?
的预编译语句,而不是client_no=" + clientNo
的字符串拼接。这将在检查不同客户端号码时获得更好的查询计划缓存。
需要注意的是,JVM需要对一个方法进行10,000次以上的调用才会开始进行JIT编译和优化。如果你的main()
方法很简单,不能使JVM预热,那么代码的执行速度会较慢。而命令行客户端已经编译成了本机代码。
我按照你的建议修改了所有的查询语句。另外,我想我也需要将DriverManagerDataSoruce
更改为DataSourceBuilder
。
+1 这个答案通过将DriverManagerDataSource
更改为SingleConnectionDataSource
,解决了我的慢速Junit测试问题。