1. 概要

データベースに出かけるのは費用がかかります。 複数のインサートを1つにまとめることで、パフォーマンスと一貫性を向上させることができる場合があります。

このチュートリアルでは、 Spring DataJPAを使用してこれを行う方法を見ていきます。

2. SpringJPAリポジトリ

まず、単純なエンティティが必要です。 それを顧客と呼びましょう:

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;

    // constructor, getters, setters 
}

次に、リポジトリが必要です。

public interface CustomerRepository extends CrudRepository<Customer, Long> {
}

これにより、 saveAll メソッドが公開され、複数の挿入が1つにバッチ処理されます。

それでは、コントローラーでそれを活用しましょう。

@RestController
public class CustomerController {   
    @Autowired
    CustomerRepository customerRepository;   

    @PostMapping("/customers")
    public ResponseEntity<String> insertCustomers() {        
        Customer c1 = new Customer("James", "Gosling");
        Customer c2 = new Customer("Doug", "Lea");
        Customer c3 = new Customer("Martin", "Fowler");
        Customer c4 = new Customer("Brian", "Goetz");
        List<Customer> customers = Arrays.asList(c1, c2, c3, c4);
        customerRepository.saveAll(customers);
        return ResponseEntity.created("/customers");
    }

    // ... @GetMapping to read customers
}

3. エンドポイントのテスト

MockMvc を使用すると、コードのテストが簡単になります。

@Autowired
private MockMvc mockMvc;

@Test 
public void whenInsertingCustomers_thenCustomersAreCreated() throws Exception {
    this.mockMvc.perform(post("/customers"))
      .andExpect(status().isCreated()));
}

4. バッチ処理してもよろしいですか?

つまり、実際には、実行する構成がもう少しあります –違いを説明するために簡単なデモを行いましょう。

まず、次のプロパティを application.properties に追加して、いくつかの統計を確認しましょう。

spring.jpa.properties.hibernate.generate_statistics=true

この時点で、テストを実行すると、次のような統計が表示されます。

11232586 nanoseconds spent preparing 4 JDBC statements;
4076610 nanoseconds spent executing 4 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;

そこで、4つの顧客を作成しました。これはすばらしいですが、いずれもバッチ内に含まれていないことに注意してください。

その理由は、バッチ処理がデフォルトでオンになっていない場合があるためです。

この場合、idの自動生成を使用しているためです。 したがって、デフォルトでは、saveAllはそれぞれ個別に挿入します。

それでは、スイッチを入れましょう:

spring.jpa.properties.hibernate.jdbc.batch_size=4
spring.jpa.properties.hibernate.order_inserts=true

最初のプロパティは、Hibernateに4つのバッチで挿入を収集するように指示します。 order_inserts プロパティは、Hibernateに、挿入をエンティティごとにグループ化して、より大きなバッチを作成する時間をとるように指示します。

したがって、2回目のテストの実行では、挿入がバッチ処理されていることがわかります。

16577314 nanoseconds spent preparing 4 JDBC statements;
2207548 nanoseconds spent executing 4 JDBC statements;
2003005 nanoseconds spent executing 1 JDBC batches;

同じアプローチを削除と更新に適用できます( Hibernateにはorder_updatesプロパティもあることを思い出してください)。

5. 結論

挿入をバッチ処理する機能により、パフォーマンスがいくらか向上することがわかります。

もちろん、バッチ処理が自動的に無効になる場合があることに注意する必要があります。出荷する前に、これを確認して計画する必要があります。

これらすべてのコードスニペットをGitHubで確認してください。