Spring Data JPA批量插入

2023/05/18

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
即可立即永久解锁本站全部文章