1. 概述

数据库操作是很昂贵的,尤其是频繁的单条插入。如果我们能将多个插入操作合并为一个批次提交,不仅可以提升性能,还能保证事务的一致性。

本篇文章将介绍如何在 Spring Data JPA 中实现批量插入。

2. Spring JPA Repository 配置

首先,我们准备一个简单的实体类,比如叫 Customer

@Entity
public class Customer {

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

    // constructor, getters, setters 
}

然后创建对应的 Repository 接口:

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

✅ 这个接口自带了 saveAll() 方法,可以用来批量插入数据

接下来,在 Controller 中使用它:

@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. 真的启用了批量插入吗?

⚠️ 实际上,默认情况下 Spring Data JPA 并不会自动启用批量插入功能

我们可以通过开启 Hibernate 的统计日志来验证这一点。

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 条记录 ✅,但注意最后一行: ❌ 没有执行任何 JDBC 批次操作!

这是因为我们使用了主键自增(@GeneratedValue),而 Hibernate 默认在这种场景下会逐条插入

✅ 启用批量插入的关键配置

我们需要手动开启 Hibernate 的批量支持:

spring.jpa.properties.hibernate.jdbc.batch_size=4
spring.jpa.properties.hibernate.order_inserts=true
  • batch_size=4:告诉 Hibernate 每次最多收集 4 条插入语句打包成一批。
  • order_inserts=true:让 Hibernate 花点时间按实体类型排序,这样可以合并更多的插入操作。

再次运行测试后,你会看到统计信息变为:

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

✅ 成功执行了 1 个批次操作!

💡 小贴士:同样的配置也适用于批量更新和删除操作(记得设置 order_updates=true)。

5. 总结

通过启用 Hibernate 的批量插入机制,我们可以在大量数据插入时显著提升性能。

不过要记住:

  • ❌ 批量插入并非默认启用;
  • ⚠️ 使用自动生成 ID 时尤其容易踩坑;
  • ✅ 正确配置 batch_sizeorder_inserts 是关键。

所以在上线前一定要做压测和验证,别被“看起来没问题”的假象骗了 😎


原始标题:Spring Data JPA Batch Inserts | Baeldung