gpt4 book ai didi

java - JDBC批处理操作理解

转载 作者:搜寻专家 更新时间:2023-10-31 08:25:14 24 4
gpt4 key购买 nike

我在我的应用程序中使用 Hibernate ORM 和 PostgreSQL,有时我使用批处理操作。起初我不明白为什么在 batch = 25 大小的日志中会生成 25 个查询,起初我认为它无法正常工作。但是之后我查看了pg驱动的源码,在PgStatement类中发现了如下几行:

 public int[] executeBatch() throws SQLException {
this.checkClosed();
this.closeForNextExecution();
if (this.batchStatements != null && !this.batchStatements.isEmpty()) {
this.transformQueriesAndParameters();
//confuses next line, because we have array of identical queries
Query[] queries = (Query[])this.batchStatements.toArray(new Query[0]);
ParameterList[] parameterLists =
(ParameterList[])this.batchParameters.toArray(new ParameterList[0]);
this.batchStatements.clear();
this.batchParameters.clear();

在 PgPreparedStatement 类中

    public void addBatch() throws SQLException {
checkClosed();
if (batchStatements == null) {
batchStatements = new ArrayList<Query>();
batchParameters = new ArrayList<ParameterList>();
}

batchParameters.add(preparedParameters.copy());
Query query = preparedQuery.query;
//confuses next line
if (!(query instanceof BatchedQuery) || batchStatements.isEmpty()) {
batchStatements.add(query);
}
}

我注意到如果批处理的大小变为 25,发送了 25 个带有附加参数的查询。

数据库的日志证实了这一点,例如:

2017-12-06 01:22:08.023 MSK [18402] postgres@buzzfactory СООБЩЕНИЕ:  выполнение S_3: BEGIN
2017-12-06 01:22:08.024 MSK [18402] postgres@buzzfactory СООБЩЕНИЕ: выполнение S_4: select nextval ('tests_id_seq')
2017-12-06 01:22:08.041 MSK [18402] postgres@buzzfactory СООБЩЕНИЕ: выполнение S_2: insert into tests (name, id) values ($1, $2)
2017-12-06 01:22:08.041 MSK [18402] postgres@buzzfactory ПОДРОБНОСТИ: параметры: $1 = 'test', $2 = '1'
2017-12-06 01:22:08.041 MSK [18402] postgres@buzzfactory СООБЩЕНИЕ: выполнение S_2: insert into tests (name, id) values ($1, $2)
2017-12-06 01:22:08.041 MSK [18402] postgres@buzzfactory ПОДРОБНОСТИ: параметры: $1 = 'test', $2 = '2'
...
x23 queries with parameters
...
2017-12-06 01:22:08.063 MSK [18402] postgres@buzzfactory СООБЩЕНИЕ: выполнение S_5: COMMIT

但我认为必须使用包含 25 个参数的数组来执行一个查询。或者我不明白批量插入如何与准备好的语句一起使用?为什么要将一个查询重复 n 次?

毕竟,我试图在这个地方调试我的查询

if (!(query instanceof BatchedQuery) || batchStatements.isEmpty()) {

并注意到我的查询始终是 SimpleQuery 而不是 BatchedQuery 的实例。也许这是解决问题的方法?我找不到有关 BatchedQuery 的信息

最佳答案

可能涉及各种批处理,我将介绍其中的 PostgreSQL JDBC 驱动程序 (pgjdbc)。

TL;DR:在使用批处理 API 的情况下,pgjdbc 确实使用了较少的网络往返。 BatchedQuery 仅在 reWriteBatchedInserts=true 传递给 pgjdbc 连接设置时使用。

您可能会找到 https://www.slideshare.net/VladimirSitnikv/postgresql-and-jdbc-striving-for-high-performance相关(幻灯片 44,...)

在执行查询时,网络延迟通常是耗用时间的重要组成部分。

假设案例是插入10行。

  1. 无批处理(例如,只是在一个循环中执行 PreparedStatement#execute)。驱动程序将执行以下操作

    execute query
    sync <-- wait for the response from the DB
    execute query
    sync <-- wait for the response from the DB
    execute query
    sync <-- wait for the response from the DB
    ...

    大部分时间会花在“等待 DB”上

  2. JDBC 批处理 API。即 PreparedStatement#addBatch() 使驱动程序能够在单个网络往返中发送多个“查询执行”。然而,当前的实现仍会将大批量拆分为较小的批量以避免 TCP 死锁。

    行动会好得多:

    execute query
    ...
    execute query
    execute query
    execute query
    sync <-- wait for the response from the DB
  3. 请注意,即使使用 #addBatch,“执行查询”命令也会产生开销。服务器确实需要花费大量时间来单独处理每条消息。

    减少查询次数的方法之一是使用多值插入。例如:

    insert into tab(a,b,c) values (?,?,?), (?,?,?), ..., (?,?,?)

    此 PostgreSQL 可以一次插入多行。缺点是您没有详细的(每行)错误消息。目前 Hibernate 没有实现多值插入。

    但是,自 9.4.1209 (2016-07-15) 以来,pgjdbc 可以将常规批量插入即时重写为多值。

    为了激活多值重写,您需要添加reWriteBatchedInserts=true 连接属性。该功能最初是在 https://github.com/pgjdbc/pgjdbc/pull/491 中开发的

    为了插入 10 行,使用 2 条语句就足够聪明了。第一个是 8 值语句,第二个是 2 值语句。使用 2 的幂使 pgjdbc 能够保持不同语句的数量不变,并且提高了性能,因为常用的语句是服务器准备的(参见 What's the life span of a PostgreSQL server-side prepared statement )

    BatchedQuery 表示那种多值语句,因此您只会在 reWriteBatchedInserts=true 情况下看到该类。

    该功能的缺点可能包括:作为“批处理结果”的细节较少。例如,常规批处理为您提供“每条语句行数”,但在多值情况下,您只会获得“语句完成”状态。最重要的是,即时重写器可能无法解析某些 SQL 语句(例如 https://github.com/pgjdbc/pgjdbc/issues/1045 )。

关于java - JDBC批处理操作理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47664889/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com