【发布时间】: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