JDBC模板运行缓慢

14 浏览
0 Comments

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);

}

}

0
0 Comments

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测试问题。

0