Spring Boot - JPA 存储库 - 批量插入不起作用

Dan*_*elp 5 spring jpa spring-boot

我正在尝试使用 JpaRepository 实现批量插入,但即使我使用推荐的属性,它似乎也不起作用。这是我的代码:

实体 - Book.java

@Entity(name = "books")
@Table(name = "books")
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;

    private String title;

    private String author;

    private String edition;

    private String status;

    @Column(unique = true)
    private String isbn;

    @JsonIgnore
    @OneToMany(cascade = CascadeType.ALL,mappedBy = "book", fetch = FetchType.LAZY)
    private List<Image> images = new ArrayList<>();

// Getters and Setters omitted

}
Run Code Online (Sandbox Code Playgroud)

服务 -BookServiceImpl


@Service
public class BookServiceImpl implements BookService {

    @Autowired
    private BookRepository bookRepository;

    @Override
    public List<Book> storeBooks(List<Book> books) {

        return bookRepository.saveAll(books);
    }
}

Run Code Online (Sandbox Code Playgroud)

特性 - application.properties

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost/bookdb?reWriteBatchedInserts=true
spring.datasource.username=**
spring.datasource.password=**

spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.jdbc.batch_size=100
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
spring.jpa.properties.hibernate.generate_statistics=true
Run Code Online (Sandbox Code Playgroud)

插入后的SQL日志:

Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)
2021-03-07 09:57:50.163  INFO 7800 --- [nio-8080-exec-1] i.StatisticalLoggingSessionEventListener : Session Metrics {
    2883700 nanoseconds spent acquiring 1 JDBC connections;
    0 nanoseconds spent releasing 0 JDBC connections;
    9612998 nanoseconds spent preparing 10 JDBC statements;
    23803401 nanoseconds spent executing 9 JDBC statements;
    23764601 nanoseconds spent executing 1 JDBC batches;
    0 nanoseconds spent performing 0 L2C puts;
    0 nanoseconds spent performing 0 L2C hits;
    0 nanoseconds spent performing 0 L2C misses;
    275826200 nanoseconds spent executing 1 flushes (flushing a total of 9 entities and 9 collections);
    0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
Run Code Online (Sandbox Code Playgroud)

我不知道问题是否出在日志或其他什么地方,但我按照建议实现了一切......

Dan*_*elp 9

我意识到批量插入已经可以工作,问题是 Hibernate 默认日志记录不显示 SQL 插入是否是批量的,因此解决方案是实现 BeanPostProcessor 并添加两个依赖项:SLF4J 和 DataSource Proxy。


@Component
public class DatasourceProxyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
        if (bean instanceof DataSource) {
            ProxyFactory factory = new ProxyFactory(bean);
            factory.setProxyTargetClass(true);
            factory.addAdvice(new ProxyDataSourceInterceptor((DataSource) bean));
            return factory.getProxy();
        }
        return bean;
    }

    private static class ProxyDataSourceInterceptor implements MethodInterceptor {
        private final DataSource dataSource;

        public ProxyDataSourceInterceptor(final DataSource dataSource) {
            super();
            this.dataSource = ProxyDataSourceBuilder.create(dataSource).countQuery().logQueryBySlf4j(SLF4JLogLevel.INFO).build();
        }

        @Override
        public Object invoke(final MethodInvocation invocation) throws Throwable {
            Method proxyMethod = ReflectionUtils.findMethod(dataSource.getClass(), invocation.getMethod().getName());
            if (proxyMethod != null) {
                return proxyMethod.invoke(dataSource, invocation.getArguments());
            }
            return invocation.proceed();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我更新了我的 pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/net.ttddyy/datasource-proxy -->
        <dependency>
            <groupId>net.ttddyy</groupId>
            <artifactId>datasource-proxy</artifactId>
            <version>1.7</version>
        </dependency>
Run Code Online (Sandbox Code Playgroud)

然后我再次测试它,我从 SLF4J 得到了这个:


2021-03-07 10:48:46.075  INFO 14044 --- [nio-8080-exec-5] n.t.d.l.l.SLF4JQueryLoggingListener      : Name:, Connection:6, Time:4, Success:True, Type:Prepared, Batch:True, QuerySize:1, BatchSize:16, Query:["insert into books (author, edition, isbn, status, title, id) values (?, ?, ?, ?, ?, ?)"], Params:[(Author 2,Edition 2,978-472-592-193-7,Owned,Book 2,33),(Author 2,Edition 2,978-412-592-193-7,Owned,Book 2,34),(Author 2,Edition 2,978-473-592-193-7,Owned,Book 2,35),(Author 2,Edition 2,978-472-552-193-7,Owned,Book 2,36),(Author 2,Edition 2,978-472-092-193-7,Owned,Book 2,37),(Author 2,Edition 2,978-402-592-193-7,Owned,Book 2,38),(Author 2,Edition 2,178-472-592-193-7,Owned,Book 2,39),(Author 2,Edition 2,278-472-592-193-7,Owned,Book 2,40),(Author 2,Edition 2,978-472-592-472-7,Owned,Book 2,41),(Author 2,Edition 2,592-472-592-123-7,Owned,Book 2,42),(Author 2,Edition 2,562-472-592-123-9,Owned,Book 2,43),(Author 2,Edition 2,978-123-562-123-9,Owned,Book 2,44),(Author 2,Edition 2,472-472-582-123-9,Owned,Book 2,45),(Author 2,Edition 2,222-472-592-123-9,Owned,Book 2,46),(Author 2,Edition 2,978-222-123-123-9,Owned,Book 2,47),(Author 2,Edition 2,978-433-502-123-9,Owned,Book 2,48)]
Run Code Online (Sandbox Code Playgroud)

资料来源: