【Spring Data JPA】save・saveAllでselectを省略する方法
はじめに
お世話になります、hosochinです
さて今回は
「Spring Data JPAでsave / saveAllでselectを省略する」
です
Spring Data JPAではsaveメソッドを実行すると
- 更新対象のキーでselect
- 同じキーのレコードがあるかどうかチェック
- あったらupdate
- なかったらinsert
という順で処理してるっぽいです
このselectを省略して処理速度を上げたいなと思ったときのメモになります
先に結論
先に結論を書いとくと、EntityクラスでPersistable<ID> のisNewメソッドをオーバーライドしてあげることで実現できます
このisNewはbooleanを返すメソッドですが、
- リターンがtrue
- selectを省略、insertを実行する
- リターンがfalse
- selectを実行、同じキーがあるかどうかでinsert or update を実行する
となっているので、trueを固定で返すようにオーバーライドしてやればselectを省略して強制insertするような挙動にできます
(ただし既に同じPrimaryKeyのレコードが存在する場合はinsertできないので、saveメソッドでエラーが返ります)
サンプル
user_tableっていうテーブルにデータを投入しようと思います
- user_table
mysql> desc user_table;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| id | varchar(5) | NO | PRI | | |
| first_name | varchar(10) | YES | | NULL | |
| last_name | varchar(10) | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
ソースコード
- Controller
@RestController
@RequestMapping("/sample")
@RequiredArgsConstructor
public class SampleController {
private final UserRepository01 userRepository01;
@PostMapping
public void post() {
List<UserEntity> entities = Arrays.asList(
new UserEntity("001", "Taro", "Tanaka"),
new UserEntity("002", "Jiro", "Suzuki")
);
userRepository01.saveAll(entities);
}
}
- Repository
import com.example.demo.domain.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository01 extends JpaRepository<UserEntity, String> {}
- Entity
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.domain.Persistable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="user_table")
@NoArgsConstructor
@AllArgsConstructor
@Getter
// Persistableをimplementsする
// 型パラメータにはプライマリキーの型を入れる
public class UserEntity implements Persistable<String> {
@Id
@Column(name = "id")
private String id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Override
public boolean isNew() {
// trueの場合、selectを省略してinsertのみ
// falseの場合、select後にupdate or insert
return true;
}
}
実行結果
// ログ確認(show-sqlをtrueにしとく)
// isNewメソッドがfalseの場合
// selectが最初に走ってからinsert(update)を実行してる
Hibernate: select userentity0_.id as id1_0_0_, userentity0_.first_name as first_na2_0_0_, userentity0_.last_name as last_nam3_0_0_ from user_table userentity0_ where userentity0_.id=?
Hibernate: select userentity0_.id as id1_0_0_, userentity0_.first_name as first_na2_0_0_, userentity0_.last_name as last_nam3_0_0_ from user_table userentity0_ where userentity0_.id=?
Hibernate: insert into user_table (first_name, last_name, id) values (?, ?, ?)
Hibernate: insert into user_table (first_name, last_name, id) values (?, ?, ?)
// isNewメソッドがtrueの場合
// selectは省略されて、いきなりinsertしている
Hibernate: insert into user_table (first_name, last_name, id) values (?, ?, ?)
Hibernate: insert into user_table (first_name, last_name, id) values (?, ?, ?)
まとめ
エンティティクラスでPersistableをimplementして、isNewメソッドをtrueにしたらselectが省略されましたね
ただ当たり前ですがすでに同じidのレコードがある場合に実行すると、
java.sql.SQLIntegrityConstraintViolationException: Duplicate entry '001' for key 'PRIMARY'
ってエラーになっちゃいますね
Persistableインターフェースについて詳しくはこちらです
ディスカッション
コメント一覧
まだ、コメントがありません