简体   繁体   中英

How the flush method in spring-data-jpa works?

I have sample project using spring-boot-2.0.3 with spring-data-jpa-2.0.3 and postgresql-9.5.13 . It has only three classes: @Entity , @Repository and main class. DB has only one table with two fields: id and name .

I'm trying to INSERT 100 000 records in the loop into the table and measure execution time - enabling or disabling flush() method from EntityManager class for each 100 records.

Expected result is that execution time with enabled flush() method is much less then with disabled one, but actually I have the opposite result.


Question: What am I doing wrong?


Project structure:

项目结构


application.properties

spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/twofold
spring.datasource.username=postgres
spring.datasource.password=postgres

User.java

package twofold.data;

import javax.persistence.*;

@Entity
@Table(name = "users", schema = "public")
public class User {

    private Long id;
    private String name;

    public User() {}

    public User(String name) {
        this.name = name;
    }

    @Id
    @SequenceGenerator(name = "users_id_seq", sequenceName = "users_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "users_id_seq")
    @Column(name = "id", nullable = false)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "name", nullable = false, length = 50)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "id: " + id + "; name: " + name + ";";
    }
}

UserRepository.java

package twofold.data;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

Application.java

package twofold;

import twofold.data.User;
import twofold.data.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Autowired
    private UserRepository userRepository;

    @PersistenceContext
    private EntityManager entityManager;

    @Bean
    public CommandLineRunner addUsers() {
        return new CommandLineRunner() {
            @Transactional
            public void run(String... args) throws Exception {
                long incoming = System.currentTimeMillis();
                for (int i = 1; i <= 100000; i++) {
                    userRepository.save(new User(i + "_name"));
                    if (i % 100 == 0) {
                        entityManager.flush();
                        entityManager.clear();
                    }
                }
                System.out.println("Time: " + (System.currentTimeMillis()-incoming));
            }
        };
    }
}

You have to set following hibernate properties.

<property name="hibernate.jdbc.batch_size" value="25" />
<property name="hibernate.order_inserts" value="true" />
<property name="hibernate.order_updates" value="true" />

Then do like this:

int entityCount = 50;
int batchSize = 25;

EntityManager entityManager = entityManagerFactory().createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();

try {
    entityTransaction.begin();
    for (int i = 0; i < entityCount; i++) {
        if (i > 0 && i % batchSize == 0) {
            entityTransaction.commit();
            entityTransaction.begin();

            entityManager.clear();
        }
        Post post = new Post(
                String.format("Post %d", i + 1)
        );
        entityManager.persist(post);
    }
    entityTransaction.commit();
} catch (RuntimeException e) {
    if (entityTransaction.isActive()) {
        entityTransaction.rollback();
    }
    throw e;
} finally {
    entityManager.close();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM