🗃️ JPA Q36 / 63

What is the difference between persist() and save()?

AI-Powered Answer ✓ Answered

`persist()` and `save()` are methods used in Java Persistence API (JPA) and Hibernate respectively to store entity objects into the database. While they achieve a similar goal of saving data, they operate under different specifications and have distinct behaviors, especially concerning transaction management and return values. Understanding their differences is crucial for effective entity management in persistence layers.

The `persist()` Method (JPA Standard)

The persist() method is part of the JPA standard (javax.persistence.EntityManager). It is used to make a transient instance persistent. Once persist() is called, the entity transitions from a 'new' (transient) state to a 'managed' (persistent) state. The entity's identity is generated, but the actual INSERT SQL statement might not be executed until flush time (e.g., transaction commit or flush() call).

  • JPA standard method, defined by EntityManager.
  • Does not return any value (void).
  • Adds a transient instance to the persistence context, making it persistent.
  • The entity remains managed after the operation.
  • Guaranteed to not execute an INSERT statement immediately but rather schedules it.
  • Cannot be used to update an existing entity; throws an EntityExistsException if called on an entity with an existing ID that is already known by the persistence context, or if it's a detached entity with an ID.
java
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();

User user = new User("John Doe", "john.doe@example.com"); // transient state
em.persist(user); // user is now in persistent state

em.getTransaction().commit();
em.close();

The `save()` Method (Hibernate Specific)

The save() method is a Hibernate-specific method (org.hibernate.Session). It also makes a transient instance persistent, but with a slight difference in behavior. It guarantees to return the identifier (primary key) of the newly saved entity immediately. This implies that save() will often execute an INSERT statement immediately to get the generated ID, especially for identity generation strategies.

  • Hibernate-specific method, defined by Session.
  • Returns the Serializable identifier (primary key) of the persisted entity.
  • Adds a transient instance to the persistence context, making it persistent.
  • The entity remains managed after the operation.
  • May execute an INSERT statement immediately to generate and return the ID.
  • Can be used on existing entities, but its behavior can be ambiguous: if an entity with the same ID already exists in the session, it might throw an exception or update it depending on configuration. If called on a detached entity with an ID, it typically re-inserts it, potentially leading to duplicate entries if not careful (often merge() is preferred for detached entities).
java
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();

Product product = new Product("Laptop", 1200.00); // transient state
Long id = (Long) session.save(product); // product is now persistent, id is generated
System.out.println("Generated Product ID: " + id);

transaction.commit();
session.close();

Key Differences Summarized

Feature`persist()` (JPA)`save()` (Hibernate)
StandardJPA standard (`EntityManager`)Hibernate specific (`Session`)
Return ValuevoidSerializable (entity's identifier)
Behavior on CallSchedules the INSERT, doesn't guarantee immediate execution. Does not generate ID until flush.Guarantees immediate ID generation (if configured) and returns it. Often triggers INSERT immediately.
State TransitionTransient -> PersistentTransient -> Persistent
Updates ExistingCannot update existing entities. Throws `EntityExistsException` if used on an entity already existing in persistence context or a detached entity with existing ID.Can potentially update if ID is explicitly set and `save-update` is configured, but primarily for new entities. Behavior on detached entities with IDs can be complex and lead to re-insertion.

When to Use Which

The choice between persist() and save() often depends on whether you are strictly adhering to JPA standards or leveraging Hibernate-specific features, and your requirements for immediate ID generation.

  • Use persist():
  • When writing portable JPA code that can run on any JPA provider (like EclipseLink, OpenJPA, Hibernate as JPA provider).
  • When you don't need the entity's generated ID immediately after the save operation.
  • For purely creating new entities and moving them into the managed state without affecting existing ones.
  • Use save():
  • When working exclusively with Hibernate and leveraging its specific API and features.
  • When you need the generated identifier (primary key) of the entity immediately after saving it.
  • For legacy Hibernate applications where save() is already established and its specific behaviors are understood and desired.

Conclusion

In modern JPA applications using Hibernate as the underlying provider, it is generally recommended to stick to the JPA standard EntityManager methods, including persist(), find(), merge(), and remove(), to maintain portability and predictability. The save() method, while functional in Hibernate, is a legacy method; for new development, persist() is generally preferred for new entities, and merge() for bringing detached entities back into a managed state or updating them.