数据库操作是非常昂贵的,我们可以通过采用批量操作提升性能并维护一致性。本文通过示例说明Spring Data JPA的批量操作。
org.springframework.boot
spring-boot-starter-data-jpa
2.1.3.RELEASE
com.h2database
h2
1.4.197
你可以选择最新版本,这里为了方便采用h2数据库。
这里简单定义实体类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 {
}
下面利用saveAll方式实现批量插入。
在Controller中注入customerRepository,调用saveAll方法实现批量插入:
@RestController
public class CustomerController {
@Autowired
CustomerRepository customerRepository;
@PostMapping("/customers")
public ResponseEntity 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 customers = Arrays.asList(c1, c2, c3, c4);
customerRepository.saveAll(customers);
return ResponseEntity.created("/customers");
}
// ... @GetMapping to read customers
}
@Autowired
private MockMvc mockMvc;
@Test
public void whenInsertingCustomers_thenCustomersAreCreated() throws Exception {
this.mockMvc.perform(post("/customers"))
.andExpect(status().isCreated()));
}
这样就完成了批量插入操作,真的能起作用吗?下面我们配置日志进行验证。
为了验证,我们在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个customer,但在批操作中没有它们。原因是在有些情况下批量操作默认没有启用,我们示例中id是自动生成的,这时saveAll缺省不采用批量操作。现在我们启用批量操作相关配置:
spring.jpa.properties.hibernate.jdbc.batch_size=4
spring.jpa.properties.hibernate.order_inserts=true
第一个属性告诉Hibernate收集插入批为4。 order_insert属性告诉Hibernate花时间按实体对插入进行分组,从而创建更大的批。
接着第二次运行测试,输出日志为:
16577314 nanoseconds spent preparing 4 JDBC statements;
2207548 nanoseconds spent executing 4 JDBC statements;
2003005 nanoseconds spent executing 1 JDBC batches;
对于更新和删除也可以使用相同的方法,Hibernate也提供了order_updates属性。
使用批量插入可以提升性能。Spring Data Jpa 在一些情况下自动禁用批量功能,需要手动启用。