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接口:
@Repository
public interface CustomerRepository extends CrudRepository<Customer, Long> {
}
这为我们公开了一个saveAll方法,它将多个插入批处理为一个。
所以,让我们在控制器中利用它:
@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测试我们的代码很简单:
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = JpaInsertApplication.class)
@AutoConfigureMockMvc
class BatchInsertIntegrationTest {
@Autowired
private CustomerRepository customerRepository;
private MockMvc mockMvc;
@BeforeEach
void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(new CustomerController(customerRepository))
.build();
}
@Test
void whenInsertingCustomers_thenCustomersAreCreated() throws Exception {
this.mockMvc.perform(post("/customers"))
.andExpect(status().isOk());
}
}
4. 什么时候使用批处理执行
因此,实际上,还有更多的配置要做-让我们做一个快速演示来说明差异。
首先,让我们将以下属性添加到application.properties以查看一些统计信息:
spring.jpa.properties.hibernate.generate_statistics=true
此时,如果我们运行测试,我们将看到如下所示的统计信息:
因此,我们创建了四个Customer,这很好,但请注意,他们都不在一个批次中。
原因是在某些情况下,批处理默认情况下不会开启。
在我们的例子中,这是因为我们使用id的生成策略为auto-generation。因此,默认情况下,saveAll()会分别执行每个插入操作。
那么,让我们其余启用它:
spring.jpa.properties.hibernate.jdbc.batch_size=4
spring.jpa.properties.hibernate.order_inserts=true
第一个属性告诉Hibernate以四个为一批收集插入语句。order_inserts属性告诉Hibernate按实体对插入进行分组,从而创建更大的批次。
因此,当我们第二次运行测试时,我们会看到插入是批处理的:
我们可以将相同的方法应用于删除和更新(记住,Hibernate也具有order_updates属性)。
5. 总结
有了批量插入的能力,我们可以看到一些性能提升。
当然,我们需要注意在某些情况下批处理是自动禁用的,我们应该在使用前检查并计划这一点。
与往常一样,本教程的完整源代码可在GitHub上获得。
Show Disqus Comments
Post Directory
扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章