如何在单个 JDBC 连接中执行多个 JPA 查询

Posted

技术标签:

【中文标题】如何在单个 JDBC 连接中执行多个 JPA 查询【英文标题】:How to Execute multiple JPA queries in a single JDBC Connection 【发布时间】:2020-02-21 02:57:18 【问题描述】:

在 Spring-boot 应用程序中,我将 JPA 与 Hibernate 一起使用。

我有一个自定义选择查询方法,在 JPA 存储库中定义了参数化的 IN 子句。由于数据量很大,我正在执行多次相同的查询,并将小批量的 ID 作为参数传递。但我无法提高性能。

大约有 200000 条记录,所用时间为 1 分钟。这是非常巨大的。

以下是我累的事情

    只选择所需的列,而不是整个 POJO -> 确实将查询时间减少了 8 秒

    当我分析 Hibernate 静态数据时:以下是找到的日志:

    ( 获取 1 个 JDBC 连接花费了 382016470 纳秒; 0 纳秒释放 0 个 JDBC 连接; 准备 1 条 JDBC 语句花费了 798909958 纳秒; 执行 1 条 JDBC 语句花费了 305523944 纳秒; 执行 0 个 JDBC 批处理花费 0 纳秒; 执行 0 个 L2C put 花费了 0 纳秒; 执行 0 个 L2C 命中花费了 0 纳秒; 0 纳秒执行 0 次 L2C 未命中; 0 纳秒执行 0 次刷新(共刷新 0 个实体和 0 个集合); 0 纳秒执行 0 次部分刷新(共刷新 0 个实体和 0 个集合)

即使使用 Hikari 连接池,创建 JDBC 连接也需要时间。以下是 hikari 属性

 spring.datasource.hikari.connection-timeout=120000
    spring.datasource.hikari.maximum-pool-size=100
    spring.datasource.hikari.minimum-idle=30
 spring.jpa.hibernate.connection.provider_class=org.hibernate.hikaricp.internal.HikariCPConnectionProvider
    spring.datasource.hikari.pool-name=HikariConnectionPool
    spring.datasource.hikari.data-source-properties.cachePrepStmts=true
    spring.datasource.hikari.data-source-properties.useServerPrepStmts=true

    并为每一个jpa查询建立JDBC连接,做好准备。 即使设置了以下属性

    spring.datasource.hikari.data-source-properties.cachePrepStmts=true spring.datasource.hikari.data-source-properties.useServerPrepStmts=true

我将 IN 子句的参数数量保持不变

代码片段

//JPA Reposistry

public interface CarRepository extends CrudRepository<Car, String>, JpaSpecificationExecutor<Car> 

@Query(SELECT u.carName as carName,
    u.carId as
    carId from
    Car u
    where u.carId in (:carIds))
List<CarP> findCarProjections@Param("carIds")Set<String> carIds);



//Service
    @Component public carService


@Autowired
CarRepository carRepo;

public void processCars(List<carId> carIds)


List<List<String>> carIdPartioned = partionCarIds(carIds)
ExecutorService es = Executors.newFixedThreadPool(10);
for(List<String> carIdPart : carIdPartioned)
es.submit(new ProcessCarInThread(carIdPart,carRepo));



//Each Call Creates a new connection to JDBC 
//Takes time to prepare Statement ( as given in hibernate statics )
class ProcessCarInThread implements Runnable

List<String> carIds;
CarRepository carRepo;
public ProcessCarInThread(List<String> carIds, CarRepository carRepo )

this.carIds=carIds;
this.carRepo=carRepo;

       @Override
    public void run() 
//query 1
List<CarP> cars=carRepo.findCarProjections(carIds);
//query 2
List<SomeotherEntity> cars=otherRepo.findSomethingElse(params);
//even query 1 and query2 is not executing in a single JDBC connection
//Do Something



我想提高性能,欢迎提出任何建议。

有什么方法可以避免 JDBC 查询准备时间或 JDBC 连接获取时间?

【问题讨论】:

【参考方案1】:

非常令人惊讶的是,我当前的应用程序在 PROD 部署后遇到了类似的性能问题。幸运的是,我们能够修复它。

根本原因:我们观察到在@Query 中使用多个输入参数会导致性能问题。

@Query(SELECT u.carName as carName, u.carId as carId from Car u where u.carId in (:carIds))

解决方案:改用entityManager 来动态形成类似的查询,性能得到显着改善

【讨论】:

如何使用实体管理器启用会话指标?使用 Entity Manager 以下是打印的指标,认为是正确的。由于执行时间显示为 0 会话指标是什么意思?您是否尝试过 entityManager 并发现性能有所提升?

以上是关于如何在单个 JDBC 连接中执行多个 JPA 查询的主要内容,如果未能解决你的问题,请参考以下文章

Impala 单个插入语句创建多个文件

我们如何使用 jdbc 执行连接查询,而不是使用 pyspark 获取多个表

在单个查询中使用 JPA 进行多个聚合

如何在 LINQ 中对单个连接中的多个字段进行连接

如何使用 JPA 1.0 构建一个 JPQL 查询,从多个表中获取数据以克服延迟初始化?

我可以为单个查询设置 JDBC 超时吗?