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_size
和order_inserts
是关键。
所以在上线前一定要做压测和验证,别被“看起来没问题”的假象骗了 😎