Spring Data JPA: Persist vs Merge

  • Post last modified:November 11, 2023
  • Reading time:3 mins read

Understanding the difference between persist() and merge()

Introduction

  • In this article, we will learn about the persist and merge method of JPA specification and when to use one over the other.

Entity Class

  • Our entity class is Account which is mapped to the 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

}

Persist()

  • When we create an entity like an account it’s initially in a transient state. When we call persist() it’s managed by persistence context and mapped to a database record.
public void persistAccount() {
        // add account to persistence context
        Account account = getAccount();
        em.persist(account);
        // updates username 
        account.setUsername("username_12345");
    }
  • persist() over entity doesn’t guarantee that it will trigger INSERT immediately, rather it will postpone until the flush is called.
  • As we can see in the logs Updates on the account entity get executed.
  • persist() method should be used for new entities, which means instance that is new and has never been created and associated with a database row.

Merge()

  • Merging is required when the entity is detached, meaning it’s not managed by the persistent context.
  • When we call merge() on the detached entity, it copies the attribute, adds to the persistence context, and returns the managed entity.
  • If the entity is new it will be created and if it exists then it will be updated.
  • All future updates on a managed entity will be tracked but updates on the detached entity will not be tracked.
  • We can see that in the below examples.
public void mergeAccount() {
    // add account to persistence context
    Account account = getAccount();
    em.merge(account);
    // updates username
    account.setUsername("username_"+UUID.randomUUID().toString());
}
  • As we can in the logs update on the account entity doesn’t get executed.
  • But an update on returned managed entity mergedInstance is tracked.
public void mergeAccount() {
     // add account to persistence context
     Account account = getAccount();
     Account mergedInstance = em.merge(account);
     // updates username on entity but doesn't get queried to the database
     String username = "username_"+UUID.randomUUID().toString();
     account.setUsername(username);
     // updates username on managed entity and get quried to the database
     mergedInstance.setUsername(username);
 }
  • We can see that update gets executed on the database when it’s called on returned mergedInstance, while updates on the account entity don’t get executed.

Conclusion

  • When we are creating a new entity it makes sense to use persist() method, which will persist the entity to persistence context and make it managed instance. Any further changes to it will be tracked and synchronized to the database.
  • If the entity is in a detached state, we can use merge() method which will update the entity if it exists or create a new one if doesn’t. The passed entity will not be managed but merge() returns manages entity as a return value which is tracked for further changes.

Before You Leave

Leave a Reply