Partner – Orkes – NPI EA (cat=Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

Browser testing is essential if you have a website or web applications that users interact with. Manual testing can be very helpful to an extent, but given the multiple browsers available, not to mention versions and operating system, testing everything manually becomes time-consuming and repetitive.

To help automate this process, Selenium is a popular choice for developers, as an open-source tool with a large and active community. What's more, we can further scale our automation testing by running on theLambdaTest cloud-based testing platform.

Read more through our step-by-step tutorial on how to set up Selenium tests with Java and run them on LambdaTest:

>> Automated Browser Testing With Selenium

Partner – Orkes – NPI EA (cat=Java)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

1. Overview

In this tutorial, we’ll take a quick look at the flush() method provided by Spring JPA.

First, we’ll learn the key abstractions involved including EntityManager and flush modes. Next, we’ll set up a sample example using Customer and CustomerAddress entities.  Then, we’ll write the integration test to see how flush() works with the two flush modes. We’ll conclude by looking at some of the key benefits as well as some considerations while using explicit flush().

2. What Is flush()?

Essentially the flush() method is a part of the EntityManager interface in JPA. EntityManager can be used to interact with the persistence context in JPA. It provides methods for managing entity lifecycle, querying entities, and performing CRUD operations on the database.

The flush() method is used to synchronize any changes made to entities managed by persistence context with the underlying database. When we invoke flush() on the EntityManager, the JPA provider in turn executes any SQL statements required to persist or update the entities in the database.

Before delving further into the correct use of this method, let’s take a look at a concept that is closely related to the working of flush() and that is the various flush modes provided by JPA.

The flush modes in JPA determine when the changes made to entities in the persistence context are synchronized with the database. The two main flush modes provided by JPA are AUTO and COMMIT.

AUTO is the default flush mode. It means that changes made to entities are automatically synchronized with the database when necessary, such as when a transaction is committed, or when a query is executed that requires up-to-date data.

On the other hand COMMIT mode delays synchronization until the transaction is committed. This means that changes made to entities will not be visible to other transactions until the current transaction is committed.

3. Example Setup

Let’s consider a simple example of two entities, Customer and CustomerAddress. The CustomerAddress entity contains the customer_id as long. Let’s define the Customer entity first:

@Entity
public class Customer {

    private String name;
    private int age;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

   // getters and setters
}

Next, let’s define the Address entity:

@Entity
public class CustomerAddress {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String street;

    private String city;

    private long customer_id;

    // ... getters and setters
}

Later on, we’ll use these two classes to test various scenarios where flush() may be required.

3.1. Setting Up the EntityManager

Before we set up an EntityManager, we need to get an instance of a class that implements the EntityManagerFactory interface:

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setDataSource(dataSource);
    emf.setPackagesToScan("com.baeldung.flush");
    emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    emf.setJpaProperties(getHibernateProperties());
    return emf;
}

For the EntityManagerFactory to be set up, we need to provide the data source and  JPA properties.

Let’s use the H2-embedded database as our sample database:

@Bean
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
      .build();

Let’s set up the properties next:

Properties getHibernateProperties() {
    Properties properties = new Properties();
    properties.setProperty("hibernate.hbm2ddl.auto", "create");
    properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
    return properties;
}

 

In the subsequent sections, we’ll use this EntityManagerFactory to create an instance of EntityManager.  We’ll use this EntityManager to test various scenarios within a transaction with and without flush().

4. flush() With FlushModeType.COMMIT

Let’s start by setting the FlushModeType to COMMIT:

entityManager.setFlushMode(FlushModeType.COMMIT);

As we mentioned at the start, FlushModeType.COMMIT delays the flushing of changes to the database until the transaction is committed. This can improve performance by reducing the number of SQL statements sent to the database during a transaction, but it also increases the risk of data inconsistency if other transactions modify the same data.

To understand the need for flush() in combination with persist() of EntityManager class, let’s first test our Customer creation and attempt to query the database for the newly created Customer without calling flush():

@Test
void givenANewCustomer_whenPersistAndNoFlush_thenDatabaseNotSynchronizedWithPersistentContextUsingCommitFlushMode() {

    entityManager.setFlushMode(FlushModeType.COMMIT);

    EntityTransaction transaction = getTransaction();
    Customer customer = saveCustomerInPersistentContext("Alice", 30);
    Customer customerInContext = entityManager.find(Customer.class, customer.getId());
    assertDataInPersitentContext(customerInContext);

    TypedQuery<Customer> retrievedCustomer = entityManager.createQuery("SELECT c FROM Customer c WHERE c.name = 'Alice'", Customer.class);

    List<Customer> resultList = retrievedCustomer.getResultList();

    assertThat(resultList).isEmpty();
    transaction.rollback();
}

Essentially, here we use the bean of type EntityManager configured earlier to get an instance of a Transaction:

EntityTransaction getTransaction() {
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();
    return transaction;

We then create the Customer and persist it using entityManager.persist(customer):

Customer saveCustomerInPersistentContext(String name, int age) {
    Customer customer = new Customer();
    customer.setName(name);
    customer.setAge(age);
    entityManager.persist(customer);
    return customer;
}

Next, we query the database to retrieve the newly created Customer object.

We find that the result of the query converted to List<Customer> is an empty list, meaning that nothing from the persistent context has been synchronized with the underlying database as the transaction has not yet been committed.

Next, keeping the FlushModeType to be COMMIT, let’s make sure we call flush() after calling persist() on the entity manager:

@Test
void givenANewCustomer_whenPersistAndFlush_thenDatabaseSynchronizedWithPersistentContextUsingCommitFlushMode() {
    entityManager.setFlushMode(FlushModeType.COMMIT);

    EntityTransaction transaction = getTransaction();
    Customer customer = saveCustomerInPersistentContext("Alice", 30);
    entityManager.flush();
    Long generatedCustomerID = customer.getId();

    Customer customerInContext = entityManager.find(Customer.class, generatedCustomerID);
    assertDataInPersitentContext(customerInContext);

    TypedQuery<Customer> retrievedCustomer = entityManager.createQuery("SELECT c FROM Customer c WHERE c.name = 'Alice'", Customer.class);

    Customer result = retrievedCustomer.getSingleResult();
    assertThat(result).isEqualTo(EXPECTED_CUSTOMER);
    transaction.rollback();
}

Here, we can see that by adding the call to flush() after calling persist(), the database is synchronized with the transactions in the persistent context. We’ll query the database and get the result back which is equal to the newly created customer entity. Importantly,  the new Customer entity has been saved already in the database even though FlushModeType is COMMIT and the transaction itself is not yet committed.

4.1. Query Across Two Entities

At this point, let’s expand our simple example to include the CustomerAddress entity as well. We want to see the potential cases where we want to explicitly call flush() involving queries across multiple tables of the database.

CustomerAddress contains a field called customer_id, which is auto-generated once the customer entity is created. We can see here that we want to save a Customer, query the database for the id and use the auto-generated id in the CustomerAddress entity:

@Test
public void givenANewCustomer_whenPersistAndFlush_thenCustomerIdGeneratedToBeAddedInAddress() {
    entityManager.setFlushMode(FlushModeType.COMMIT);
    EntityTransaction transaction = getTransaction();

    saveCustomerInPersistentContext("John", 25);
    entityManager.flush();

    Customer retrievedCustomer = entityManager.createQuery("SELECT c FROM Customer c WHERE c.name = 'John'", Customer.class)
      .getSingleResult();
    Long customerId = retrievedCustomer.getId();

    CustomerAddress address = new CustomerAddress();
    address.setCustomer_id(customerId);
    entityManager.persist(address);
    entityManager.flush();

    CustomerAddress customerAddress = entityManager.createQuery("SELECT a FROM CustomerAddress a WHERE a.customer_id = :customerID", CustomerAddress.class)
      .setParameter("customerID", customerId)
      .getSingleResult();

    assertThat(customerAddress).isNotNull();
    transaction.rollback();
}

In the end, let’s quickly touch upon the use of rollback() in relation to the flush() method. Essentially, when we call rollback(), any changes made within a transaction are undone. The database is restored to its state before the transaction began. In all the scenarios we’ve been testing above, we have called rollback() at the endThis prevents any partial changes from being committed to the database, which could lead to data inconsistencies or corruption.

5. flush() With FlushModeType.AUTO

Next, let’s see what happens when we use flush() with the FlushModeType set to AUTO.

We’ll set the flush mode to AUTO first:

entityManager.setFlushMode(FlushModeType.AUTO);

 Here the JPA automatically detects when a flush is needed and performs it before executing the query. This ensures that the query results are up-to-date and that any changes made to persistent objects are persisted in the database. Therefore there’s no need to explicitly call flush() here:

@Test
void givenANewCustomer_whenPersistAndNoFlush_thenDBIsSynchronizedWithThePersistentContextWithAutoFlushMode() {
    entityManager.setFlushMode(FlushModeType.AUTO);
    EntityTransaction transaction = getTransaction();

    Customer customer = saveCustomerInPersistentContext("Alice", 30);
    Customer customerInContext = entityManager.find(Customer.class, customer.getId());
    assertDataInPersitentContext(customerInContext);

    TypedQuery<Customer> retrievedCustomer = entityManager.createQuery("SELECT c FROM Customer c WHERE c.name = 'Alice'", Customer.class);

    Customer result = retrievedCustomer.getSingleResult();

    assertThat(result).isEqualTo(EXPECTED_CUSTOMER);
    transaction.rollback();
}

The test shows that we haven’t called any flush() after persist(). Still, we can see that querying the Customer table returns the TypedQuery<Customer>, which is equal to the Customer object which was present in the persistent context.

There’s no need for explicit flush() to synchronize the entity in the persistent context with the database since the FlushModeType is AUTO.

Let’s again test the Customer and CustomerAddress creation scenario when the mode is AUTO:

@Test
public void givenFlushModeAutoAndNewCustomer_whenPersistAndNoFlush_thenCustomerIdGeneratedToBeAddedInAddress() {
    entityManager.setFlushMode(FlushModeType.AUTO);
    EntityTransaction transaction = getTransaction();

    saveCustomerInPersistentContext("John", 25);

    Customer singleResult = entityManager.createQuery("SELECT c FROM Customer c WHERE c.name = 'John'", Customer.class)
      .getSingleResult();
    Long customerId = singleResult.getId();

    CustomerAddress address = new CustomerAddress();
    address.setCustomer_id(customerId);
    entityManager.persist(address);

    CustomerAddress customerAddress = entityManager.createQuery("SELECT a FROM CustomerAddress a WHERE a.customer_id = :customerID", CustomerAddress.class)
      .setParameter("customerID", customerId)
      .getSingleResult();

    assertThat(customerAddress).isNotNull();
    transaction.rollback();
}

As expected, here as well, with the AUTO mode, the flush() is not needed and we can query the Customer in the database before the CustomerAddress is created while the transaction is still ongoing.

Next, let’s look at some of the key benefits followed by potential issues in using flush() explicitly.

6. Benefits of Explicit flush()

Here are some of the benefits of explicit flush():

  • Consistency: We can be sure that the database is synchronised with the persistent context as soon as flush() is called and therefore have real-time consistency across the two components.
  • Improved performance: When used properly, we can reduce the number of SQL statements sent to the database by grouping related changes into a single batch. This can lead to improved performance, particularly if we are making many changes to the same set of objects.
  • Immediate feedback: Any pending changes are written to the database immediately when we call flush(). This can provide immediate feedback on the success or failure of the operation, which will be useful for debugging and troubleshooting.
  • Better resource management: By flushing changes to the database as soon as they are made, we can reduce the memory and other resources required to hold pending changes until the end of the transaction.

7. Potential Issues of Explicit flush()

However, we must be aware of potential issues that can be caused by improper or frequent calls to flush():

  • Database contention: when using flush() we can potentially face database contention. This is most probable if multiple transactions are trying to access the same set of data. This can lead to locks, deadlocks, and other database-related issues.
  • Increased memory usage: When called too frequently, it can result in increased memory usage, particularly if we are making many changes to the same set of objects. This can lead to out-of-memory errors and other memory-related issues.
  • Inefficient use of database connections: When called too frequently, flush() can result in inefficient use of database connections. Each call to flush() requires a new round trip to the database, which can lead to connection pool exhaustion and other connection-related issues.
  • Data integrity issues: flush() can result in data integrity issues, particularly if we are not careful about the order in which changes are made. This can lead to inconsistencies and errors in the data stored in the database.

Overall, it’s important to use flush() judiciously and only when necessary, taking into account the potential impact on performance, memory usage, and data integrity. It’s also important to optimize our use of flush() by grouping related changes and minimizing the number of SQL statements sent to the database.

8. Conclusion

In this article, we looked at the correct use of flush() using two flush modes. We created various integration tests to see how flush() can be used correctly under various scenarios. Lastly, we discussed the pros and cons of using the method.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

Partner – Orkes – NPI EA (cat = Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – LSD – NPI (cat=JPA)
announcement - icon

Get started with Spring Data JPA through the reference Learn Spring Data JPA:

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)