2
0

More than 1 year has passed since last update.

【Spring Data JPA】主キーが重複した複数のデータをsaveAll()で登録すると・・・

Last updated at Posted at 2022-02-17

現在参画している案件でJava使い、開発を行っています。
そこでsaveAll()を用いてデータを登録する機会がありました。
しかし、実際にテストで動かしてみると3件データを登録できるはずがなぜか1件しか登録が出来ていなかったのです。

#原因
テスト自体は通るのですが、エラーで落ちてはいない・・・
なぜ登録できなかったのか、それは重複した主キーを複数のデータに登録していたからです。
実は開発中のAPIの仕様が曖昧なところがあり、""(空文字)で指定しておいてくださいと指示を受け、主キーに全て空文字を登録するようなロジックを作成していたことが原因でした。
(そもそも主キーに空文字を登録する時点で気づくべきだった・・・)

しかしここで、また1つ疑問が浮かびました。
なぜ、重複した主キーなのにデータを登録できているんだろう???(しかもなぜか1件だけ)
その答えはsaveAll()の仕様にありました。

#saveAll()の仕様
どうやらsaveAll()は
①登録する際に重複する主キーがなかったら登録(insert)
②登録する際に重複する主キーがあったら更新(update)
という仕様になっているようです・・・

↓saveAll()を掘り下げてる記事↓
https://hosochin.com/2020/08/16/post-589/

#解決策
①複合キーを使う
・複合キーとは2つ以上のキーをもつテーブルのことです。
例)

Person.java

@Entity
@Data
@Table(name="person")
@IdClass(value=PersonKey.class)
public class Person implements Serializable {

  @Id
  @Column(name="person_id")
  private Integer personId;

  @Id
  @Column(name="employment_date")
  private String employmentDate;

  @Column(name="age")
  private Integer age;

  @Column(name="gender")
  private String gender;

  @Column(name="person_name")
  private String person_name;

  @Data
  @NoArgsConstructor
  @AllArgsConstructor
  public static class PersonKey implements Serializable {
    private Integer personId;
    private String employmentDate;
  }
}

@IdClassでPrimaryKeyを定義したクラスを指定します
@IdClassで指定したクラスに、@Idを付与しているカラムを定義します。

以上で複合キーの完成です。
これでどちらかが""(空文字)であっても、もう片方が違う値なら登録されます。

②そもそも重複するようなロジックにしない。
これに尽きます。
(そもそも""(空文字)指定の前提がおかしいような・・・??)

#終わり
以上、saveAll()や複合キーについてまとめてみました。
saveAll()が登録の他に更新も行うことは、この問題が起きるまでまったく知りませんでした。
皆様もsaveAll()を使うときはお気を付けてください。
意図せず更新をかけてしまう可能性もありますので・・・

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0