Do we need to explicitly call save() method in Hibernate or JPA to save entities?

No, you typically don’t need to explicitly call the save() method in Hibernate or JPA to save entities. In JPA, when you modify a managed entity (an entity that was retrieved or persisted by the entity manager), the changes are automatically synchronized with the database when the transaction commits. Hibernate, being an implementation of JPA, follows this behavior.

Here’s how it generally works:

  1. Persisting new entities: When you create a new entity object and persist it using EntityManager.persist() (or Session.save() in Hibernate), the entity becomes managed by the persistence context. Any changes made to this entity within the scope of the transaction will be automatically synchronized with the database upon transaction commit.
    entityManager.persist(entity);
    
  2. Updating existing entities: When you retrieve an entity from the database (either by EntityManager.find() or through a query), any changes made to this managed entity will also be synchronized with the database upon transaction commit. You don’t need to call any explicit save method.
    Entity entity = entityManager.find(Entity.class, id);
    entity.setSomeProperty(newValue);
    // Changes to 'entity' are automatically synchronized with the database upon transaction commit
    
  3. Automatic dirty checking: Hibernate/JPA employs the concept of dirty checking. It tracks the changes made to managed entities within a transaction. When the transaction commits, it automatically detects the changes and synchronizes them with the database.
    // Entity retrieved and modified within a transaction
    Entity entity = entityManager.find(Entity.class, id);
    entity.setSomeProperty(newValue);
    // Changes to 'entity' are automatically tracked and synchronized with the database upon transaction commit
    

Explicitly calling save() might be necessary in specific cases where you’re dealing with detached entities (entities that are not managed by the persistence context) or if you’re operating outside a transaction boundary, but in general usage within a transaction, it’s not required.

How do I create JPA EntityManagerFactory?

In this code snippet you will learn how to create JPA EntityManagerFactory. This factory enable you to create the EntityManager which will be used to execute the JPA command to manipulate the database tables.

To create the EntityManagerFactory you need to create to persistence.xml file first. The file is where you configure the JPA. This file must be placed inside the META-INF directory in your program working directory.

Here is an example of the persistence.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">

    <persistence-unit name="music" transaction-type="RESOURCE_LOCAL">
        <class>org.kodejava.jpa.entity.Artist</class>
        <class>org.kodejava.jpa.entity.Genre</class>
        <class>org.kodejava.jpa.entity.Label</class>
        <class>org.kodejava.jpa.entity.Record</class>
        <class>org.kodejava.jpa.entity.Review</class>
        <class>org.kodejava.jpa.entity.Reviewer</class>
        <class>org.kodejava.jpa.entity.Track</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/musicdb" />
            <property name="javax.persistence.jdbc.user" value="music" />
            <property name="javax.persistence.jdbc.password" value="s3cr*t" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
    </persistence-unit>

</persistence>

The persistence unit defined in the persistence.xml file contains a set of entities object. We also define some properties related to the database connections including the JDBC driver class, JDBC url, the username and password for opening the connection to database.

After defining the persistence.xml file we’ll create a simple program to create the EntityManagerFactory. To create the factory we can use the javax.persistence.Persistence class createEntityManagerFactory() method and pass the persistence unit name as the parameter. In this example the persistence unit name is music as can be seen in the persistence.xml file.

After we have the factory object created we can then create an EntityManager by calling the createEntityManager() of the factory object. Let’s see the code snippet below.

package org.kodejava.jpa;

import org.kodejava.jpa.entity.Artist;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class EntityManagerFactoryExample {
    public static final String PERSISTENCE_UNIT_NAME = "music";

    public static void main(String[] args) {
        EntityManagerFactory factory =
                Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        EntityManager manager = factory.createEntityManager();

        // Do something with the entity manager.
        Artist artist = manager.find(Artist.class, 1L);
        System.out.println("artist = " + artist);
    }
}

The Artist entity class definition.

package org.kodejava.jpa.entity;

import javax.persistence.*;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;

@Entity
@Table(name = "artist")
public class Artist implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;

    private Long id;
    private String name;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "name", length = 100, nullable = false)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Artist artist = (Artist) o;
        return Objects.equals(id, artist.id) &&
                Objects.equals(name, artist.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name);
    }

    @Override
    public String toString() {
        return "Artist{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

Our project directory structure.

├─ pom.xml
└─ src
   └─ main
      ├─ java
      │  └─ org
      │     └─ kodejava
      │        └─ jpa
      │           ├─ EntityManagerFactoryExample.java
      │           └─ entity
      │              ├─ Artist.java
      │              ├─ Genre.java
      │              ├─ Label.java
      │              ├─ Record.java
      │              ├─ Review.java
      │              ├─ Reviewer.java
      │              └─ Track.java
      └─ resources
         └─ META-INF
            └─ persistence.xml

Maven Dependencies

<dependencies>
    <dependency>
        <groupId>javax.persistence</groupId>
        <artifactId>javax.persistence-api</artifactId>
        <version>2.2</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.6.9.Final</version>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.1.0</version>
    </dependency>
</dependencies>

Maven Central Maven Central Maven Central