簡體   English   中英

Spring Jpa 批量插入整個數據或更新實體的某些字段(如果已經可用)

[英]Spring Jpa Bulk Insert whole data or Update some fields of entity if already available

問題:我有一個正在運行的進程,它會定期從外部抓取 500 條記錄並將其插入數據庫。 如何使用 spring JPA 在以下情況下有效檢查,

  1. 如果沒有記錄(非 primary_key 列也是唯一的),如何插入數據?
  2. 如果有記錄,如何只更新某些字段?

或者

如何使用 Spring JPA 對所有列或僅選定列的批量記錄進行保存或更新?

如果您查看Spring Data JPA的源代碼,您會發現:

@Transactional
public <S extends T> S save(S entity) {

  if (entityInformation.isNew(entity)) {
    em.persist(entity);
    return entity;
  } else {
    return em.merge(entity);
  }
}

save操作是添加和更新的混合。 因此,通過使用save()saveAll()方法,您已經實現了saveOrUpdate的 function。

要更好地控制上述 upsert 行為,您可以在實體 class 上使用@DynamicUpdate注釋,這意味着由 JPA 生成的更新 SQL 將僅訪問更改的列。

以上信息不足以在您的情況下正確使用 JPA。 如果選擇 JPA,則必須以object方式進行數據庫訪問。 要處理 500 條記錄, unique信號必須由以下條件之一定義:

  • 主鍵
  • 唯一約束

我建議您使用第二個,因為主鍵用於在數據庫級別標記唯一性。 然后,使用 JPA,您應該在數據庫中找到新的 500 條記錄中存在的數據,更新它們修改的列,使用saveAll()更新它們。 然后處理左側部分,構建實體並使用saveAll()插入它們。

您可能已經注意到我上面使用compare and update then save operation in memory不是原子的,並且在插入重復數據時可能會導致ConstraintViolationException ,有兩種處理方法:

  • 如果數據不是那么嚴重,您可以只執行上述操作,但為異常發生保留一些空間,您可以記錄信息以進行手動修復或什么也不做。 但記住要捕獲異常,不要讓更新操作回滾。
  • 如果你確實對數據很認真,你可以使用synchronized關鍵字或分布式鎖來使整個操作同步。

老實說,我對批量 upsert 上的 JPA 不滿意,它不是原子的,不安全的,也不快。 我認為這是因為在所有 DBMS 中都沒有普遍實現的upsert模式,因此 ORM 部分放棄了 function。 我真誠地建議您對系統選擇的數據庫實現的原始 SQL 使用upsert操作,例如 MYSQL INSERT... ON DUPLICATE KEY UPDATE Statement 下面的示例代碼:

  public int upsert(List<Employee> employees) {

      String sqlPattern = "INSERT INTO employee (id, code, name)\n" 
              + "VALUES %s\n"
              + "ON DUPLICATE KEY UPDATE name      = values(name);";

      List<String> values = employees.stream()
              // build something like (1, '10001', 'Foo Bar')
              .map(employee -> buildRecord(employee))
              .collect(Collectors.toList());

      String sql = String.format(sqlPattern, StringUtils.join(values, ", "));

      return jdbcTemplate.update(sql, Map.of());
  }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM