What is the difference between persist() and save()?
`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
EntityExistsExceptionif 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.
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
Serializableidentifier (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).
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) |
|---|---|---|
| Standard | JPA standard (`EntityManager`) | Hibernate specific (`Session`) |
| Return Value | void | Serializable (entity's identifier) |
| Behavior on Call | Schedules 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 Transition | Transient -> Persistent | Transient -> Persistent |
| Updates Existing | Cannot 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.