【问题标题】:Hibernate+ postgres batch update does not workHibernate+ postgres 批量更新不起作用
【发布时间】:2021-07-23 06:29:36
【问题描述】:

有没有办法批量更新?

我创建了一个简单的实体

@Entity
@Getter
@Setter
public class A {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "A_ID_GENERATOR")
  @SequenceGenerator(name = "A_ID_GENERATOR", sequenceName = "a_id_seq")
  private Long id;

  private String name;
}

下一步我生成了10000个A类的对象,并把它们放到db中

下一步我从 db 获取 A 列表,设置新名称并再次保存它们

  @PutMapping
  @Transactional
  public String updateAllTest(){
    var list=aRepository.findAll();

    for (int i = 0; i <list.size() ; i++) {
      list.get(i).setName("AA"+i);

    }
    return "OK";
  }

我期待什么 - 我希望 hibernate 会进行批量更新 hibernate 做到了——hibernate 统计数据说——它执行 200 个批次(批次大小=500)

接下来我转到 db 日志文件,我在那里看到的 - 没有批次 - 只有单个更新 -10 000 行

在不向 JDBC 驱动程序添加 reWriteBatchedInserts=true 的情况下,它看起来与批量插入相同

那么有没有办法在 postgres 中使用 hibernate 进行批量更新?

【问题讨论】:

  • 如果你没有配置hibernate来做批量更新,你需要设置批量大小,插入/更新语句的顺序,最后你的数据库需要支持它(这可能需要调整Jdbc 驱动程序上的设置)。最后在控制器上使用@Transactional 不是最好的方法,而是将其移动到服务中(甚至可能这个@Transactional 最终被忽略了)。
  • hibernate 被配置为批量插入/更新。我在 application.yaml 中有这个配置 hibernate:jdbc: batch_size: 500 fetch_size: 1000 order_inserts: true order_updates: true
  • @transactioanal 在控制器上是典型的方式,如果你不在 spring boot 中使用 open-in-view
  • 如果我将@transactional 转移到服务中-我永远不会在同一个事务中执行此操作,因为 hibernate 会脏检查所有这些 findAll 和 saveAll 将在同一个事务中,否则您将输掉这场比赛;)
  • 您必须将所有内容移至服务方法。在控制器上使用@Transactional 可能会导致令人惊讶的效果和难以调试的问题,尤其是在映射停止工作时(由于正在创建代理)。请不要在 cmets 中添加其他信息,而是编辑您的问题。这并不是一种真正的典型方式,因为它基本上或多或少与开放式视图相同(但这是另一个完全不同的讨论)。

标签: java postgresql hibernate


【解决方案1】:

要理解的关键是,为多次执行重用相同的服务器端语句句柄是批处理。日志只是告诉你每次执行的情况,但这并不意味着它很慢。它正在做它应该做的事情。

【讨论】:

    猜你喜欢
    • 2017-12-31
    • 2014-08-24
    • 1970-01-01
    • 2012-02-16
    • 2021-04-23
    • 1970-01-01
    • 2020-06-03
    • 2019-08-17
    • 2018-10-22
    相关资源
    最近更新 更多