Spring Data JPA: Persist Vs Flush

  • Post last modified:August 27, 2023
  • Reading time:4 mins read

Understanding the difference between persist and flush

Introduction

  • JPA provides methods that can be used either add a new entity or update an existing entity or execute the query against the database.
  • Understanding the functionality is good to not have unexpected issues.
  • In this article, we will discuss two such methods i.e., persist() and flush().

Entity Class

  • Our entity class is Account which is mapped to ACCOUNTS table in the database.
@Entity
@Table(name="ACCOUNTS")
public class Account {
    @Id @GeneratedValue(strategy= GenerationType.SEQUENCE, generator = "accounts_seq")
    @SequenceGenerator(name = "accounts_seq", sequenceName = "accounts_seq", allocationSize = 1)
    @Column(name = "user_id")
    private int userId;
    private String username;
    private String password;
    private String email;
    private Timestamp createdOn;
    private Timestamp lastLogin;

    @OneToOne
    @JoinColumn(name = "permissions_id")
    private Permission permission;
    // getters and setters
}

AccountLogic Class

  • Account logic is a service class that uses a repository to interact with the database.
@Service
public class AccountLogic {

    @Autowired
    private AccountRepository accountRepository;

    @Autowired
    private PermissionRepository permissionRepository;

    @PersistenceContext
    private EntityManager em;

    // service methods
}

Building Account Entity

  • We have this private helper method that builds the account entity which we will use further to persist the entity.
private Account getAccount() {
    Permission permission = permissionRepository.findByType("1");
    Account account = new Account();
    String seed = UUID.randomUUID().toString();
    account.setUsername("username_"+seed);
    account.setEmail("username_"+seed+"@gmail.com");
    account.setPermission(permission);
    account.setPassword("password_q1234");
    account.setCreatedOn(Timestamp.from(Instant.now()));
    account.setLastLogin(Timestamp.from(Instant.now()));
    return account;
}

Persist() Method

  • Persist method takes the new entity or existing entity and adds to the persistence context.
public void flush(){
        Account account = getAccount();
        em.persist(account);
    }
  • When we call persist() on the entity, that doesn’t mean that entity gets inserted into the database immediately, that means the entity will now be managed by persistentContext, and insert to the database will happen with a flush() call depending on when EntityManager feels it might need to query the pending work in persistentContext.
  • By default, flush is automatically managed and we don’t have to call it explicitly. But if we need we can call it and the insertion of the record will happen immediately to the database.
 public void persist(){
    Account account = getAccount();
    em.persist(account); // persisted to persistenceContext but not flushed to DB Yet
    System.out.println("===============");
    permissionRepository.findByType("reader"); //no need to flush yet since don't need it
    System.out.println("===============");
    accountRepository.findAll(); 
    // since above query might need persisted account entity thats 
    // not flushed to the db yet, 
    // hence flushed will be called before the execution of below query
 }
  • As we can see records were not flushed to the database until it was needed in findAll().

Flush() method

  • By invoking entitymanager#flush method we can immediately synchronize the current persistence context to the underlying database.
  • So that means in the current example, If we want to flush our account entity that is persisted, we can call flush immediately after persisting and it will query the database without waiting for the right time.
  public void persist(){
        Account account = getAccount();
        em.persist(account);
        em.flush();
    }

One point to note here is that although flush executes any pending query to the database that data will not be committed until the transaction is committed. Flushed changes will be part of the transaction and get committed with the transaction commit.

Understanding FlushMode

  • JPA specification provides AUTO and COMMIT flush mode types. If we use Hibernate we get two additional flush mode types which are MANUAL and ALWAYS, which we will cover in a different article.

FlushModeType.AUTO

  • In this mode, the automatic flush can be invoked before the transaction commit.
  • This is up to TransactionManager when to invoke it. this is the default mode.

FlushModeType.COMMIT

  • Flushing will only execute when transactions get committed or flush is called manually.

Conclusion

  • Persist method will not call the underlying database immediately but will manage the entity as part of the persistence context and flush it when TransactionManager finds its need to flush any pending changes before moving forward.
  • By postponing the flush until needed JPA can take advantage of performance improvement like it will not use database resources until it really needs.

Before You Leave

Leave a Reply