Bra*_*rks 5 java spring-boot spring-repositories
我必须一次更新插入数千条记录,分成几批,比如说一次 25 个实际更新插入。upsert 基于 service+key 的唯一约束,如果插入失败,则会更新值。
请注意,我对 UPSERT 情况感兴趣,而不仅仅是标准插入,因为我想避免额外的数据库读取操作,并且这些数据大部分是静态的。
我将 Spring 与 Postgres 14 结合使用,并认为我应该执行类似以下操作来在 Repository 类中执行更新插入,但希望确保如果可能的话,更新插入是批量完成的。
我已经设置了以下 Spring Boot 属性,但没有看到任何表明正在发生批处理的日志消息:
spring.jpa.properties.hibernate.jdbc.batch_size = 25
spring.jpa.properties.hibernate.order_inserts = true
Run Code Online (Sandbox Code Playgroud)
我可以使用这样的方法来做到这一点,还是我必须用另一种方式来做到这一点,就像可能的那样?
spring.jpa.properties.hibernate.jdbc.batch_size = 25
spring.jpa.properties.hibernate.order_inserts = true
Run Code Online (Sandbox Code Playgroud)
编辑:我的目标是只批量执行数据库插入或更新(每批单个事务),如果值没有更改,则不执行任何操作。因此,对于尚未插入任何值的新“服务”,我将一次插入大约 5000 个值,我想确保这是分组完成的,以避免 Postgres 过载并导致大量事务日志。
编辑2:请注意,如果您使用@DataJpaTest 来测试您的upsert,H2 数据库将会失败,因为它不支持`INSERT ON CONFLICT(unique) UPDATE。更多详情请点击此处
大多数其他答案都提到了GenerationType.IDENTITY与休眠批处理属性相关的内容,例如等,但是只有当您通过其脏检查机制或的脏jdbc.batch_size检查机制以休眠方式批量更新记录时,这些事情才重要。如果您使用本机 SQL 进行更新,则与这些设置无关。EntityManagerpersist()merge()
从根本上来说,批量执行本机 SQL 需要使用 JDBC 2.0 Batch API,但没有简单的方法可以通过 hibernate API 访问这些 API。因此,我建议使用JdbcTemplate其中的batchUpdate()方法,该方法将委托给 JDBC 2.0 Batch APIPreparedStatement#addBatch()来完成实际工作。
鉴于您已经拥有本机 upsert SQL,实际上通过JdbcTemplate.
首先,定义一条记录my_table:
public record MyTable(String service, String key, String value, int version){}
Run Code Online (Sandbox Code Playgroud)
然后实现一个服务来更新它们:
@Service
public class MyTableService {
@Autowired
NamedParameterJdbcTemplate jt;
@Transactional
public void upsert(List<MyTable> rows) {
String sql = "INSERT INTO my_table "
+ " (service, key, value, version) "
+ "VALUES "
+ " (:service, :key, :value, :version) "
+ "ON CONFLICT ON CONSTRAINT allow_one_value_per_service_key DO "
+ " UPDATE "
+ " SET "
+ " value = excluded.value, version=my_table.version + 1 "
+ " WHERE "
+ " my_table.value <> excluded.value";
MapSqlParameterSource[] params = rows.stream().map(r -> {
MapSqlParameterSource paramValues = new MapSqlParameterSource();
paramValues.addValue("service", r.service());
paramValues.addValue("key", r.key());
paramValues.addValue("value", r.value());
paramValues.addValue("version", r.version());
return paramValues;
}).toArray(MapSqlParameterSource[]::new);
jt.batchUpdate(sql, params);
}
}
Run Code Online (Sandbox Code Playgroud)
使用它:
public record MyTable(String service, String key, String value, int version){}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1311 次 |
| 最近记录: |