1. 序章

EntityManagerはJavaPersistenceAPIの一部です。 主に、JPA2.0仕様で定義されているプログラミングインターフェイスとライフサイクルルールを実装します。

さらに、 EntityManager のAPIを使用して、永続性コンテキストにアクセスできます。

このチュートリアルでは、 EntityManager の構成、タイプ、およびさまざまなAPIを確認します。

2. Mavenの依存関係

まず、Hibernateの依存関係を含める必要があります。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.4.0.Final</version>
</dependency>

使用しているデータベースによっては、ドライバーの依存関係も含める必要があります。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.13</version>
</dependency>

hibernate-coreおよびmysql-connector-javaの依存関係は、MavenCentralで使用できます。

3. 構成

次に、データベース内のMOVIEテーブルに対応する Movie エンティティを使用して、EntityManagerのデモを行います。

この記事では、 EntityManager APIを使用して、データベース内のMovieオブジェクトを操作します。

3.1. エンティティの定義

@Entity アノテーションを使用して、MOVIEテーブルに対応するエンティティを作成することから始めましょう。

@Entity
@Table(name = "MOVIE")
public class Movie {
    
    @Id
    private Long id;

    private String movieName;

    private Integer releaseYear;

    private String language;

    // standard constructor, getters, setters
}

3.2. persistence.xmlファイル

EntityManagerFactory が作成されると、永続性実装はクラスパスでMETA-INF/persistence.xmlファイルを検索します。

このファイルには、EntityManagerの構成が含まれています。

<persistence-unit name="com.baeldung.movie_catalog">
    <description>Hibernate EntityManager Demo</description>
    <class>com.baeldung.hibernate.pojo.Movie</class> 
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
        <property name="hibernate.hbm2ddl.auto" value="update"/>
        <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/moviecatalog"/>
        <property name="javax.persistence.jdbc.user" value="root"/>
        <property name="javax.persistence.jdbc.password" value="root"/>
    </properties>
</persistence-unit>

ご覧のとおり、EntityManagerによって管理される基盤となるデータストアを指定する永続性ユニットを定義します。

さらに、基になるデータストアの方言とその他のJDBCプロパティを定義します。 Hibernateはデータベースに依存しません。これらのプロパティに基づいて、Hibernateは基盤となるデータベースに接続します。

4. コンテナおよびアプリケーション管理EntityManager

基本的に、 EntityManagerには、コンテナ管理とアプリケーション管理の2つのタイプがあります。

それぞれのタイプを詳しく見ていきましょう。

4.1. コンテナ管理EntityManager

ここで、コンテナーはエンタープライズコンポーネントにEntityManagerを挿入します。

つまり、コンテナはEntityManagerFactoryからEntityManagerを作成します。

@PersistenceContext
EntityManager entityManager;

これは、コンテナがトランザクションの開始と、トランザクションのコミットまたはロールバックを担当することも意味します。

同様に、コンテナは EntityManager、を閉じる責任があるため、手動でクリーンアップせずにを安全に使用できます。 コンテナ管理のEntityManager閉じようとしても、IllegalStateException。をスローする必要があります。

4.2. アプリケーション管理EntityManager

逆に、EntityManagerのライフサイクルはアプリケーションによって管理されます。

実際、 EntityManager を手動で作成し、そのライフサイクルを管理します。

まず、 EntityManagerFactory:を作成しましょう

EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.baeldung.movie_catalog");

EntityManager を作成するには、 EntityManagerFactorycreateEntityManager()を明示的に呼び出す必要があります。

public static EntityManager getEntityManager() {
    return emf.createEntityManager();
}

私たちが作成する責任があるので EntityManager インスタンス、それらを閉じることも私たちの責任です 。 したがって、 近い EntityManager それらを使い終わったら。

4.3. スレッドセーフ

EntityManagerFactoryインスタンス、したがってHibernateのSessionFactoryインスタンスは、スレッドセーフです。 したがって、並行コンテキストで次のように記述することは完全に安全です。

EntityManagerFactory emf = // fetched from somewhere
EntityManager em = emf.createEntityManager();

一方、 EntityManagerインスタンスはスレッドセーフではなく、スレッドが制限された環境で使用することを目的としています。 これは、各スレッドがそのインスタンスを取得して操作し、最後に閉じる必要があることを意味します。

アプリケーション管理のEntityManagerを使用する場合、スレッドに制限されたインスタンスを簡単に作成できます。

EntityManagerFactory emf = // fetched from somewhere 
EntityManager em = emf.createEntityManager();
// use it in the current thread

ただし、コンテナ管理の EntityManager を使用すると、直感に反します。

@Service
public class MovieService {

    @PersistenceContext // or even @Autowired
    private EntityManager entityManager;
    
    // omitted
}

1つのEntityManagerインスタンスをすべての操作で共有する必要があるようです。 ただし、コンテナー(JakartaEEまたはSpring)は、ここで単純なEntityManagerの代わりに特別なプロキシーを挿入します。 たとえば、Springはタイプのプロキシを注入します SharedEntityManagerCreator。 

挿入されたEntityManagerを使用するたびに、このプロキシは既存の EntityManager を再利用するか、新しいプロキシを作成します。 再利用は通常、次のようなものを有効にしたときに発生しますビューでSession/EntityManagerを開きます。 

いずれにせよ、コンテナーは、各EntityManagerが1つのスレッドに制限されることを保証します。

5. Hibernateエンティティ操作

EntityManager APIは、メソッドのコレクションを提供します。 これらのメソッドを利用することで、データベースを操作できます。

5.1. 永続的なエンティティ

オブジェクトをEntityManagerに関連付けるために、 persist()メソッドを使用できます。

public void saveMovie() {
    EntityManager em = getEntityManager();
    
    em.getTransaction().begin();
    
    Movie movie = new Movie();
    movie.setId(1L);
    movie.setMovieName("The Godfather");
    movie.setReleaseYear(1972);
    movie.setLanguage("English");

    em.persist(movie);
    em.getTransaction().commit();
}

オブジェクトがデータベースに保存されると、persistent状態になります。

5.2. エンティティの読み込み

データベースからオブジェクトを取得するために、 find()メソッドを使用できます。

ここでは、メソッドは主キーで検索します。 実際、このメソッドはエンティティクラスタイプと主キーを想定しています。

public Movie getMovie(Long movieId) {
    EntityManager em = getEntityManager();
    Movie movie = em.find(Movie.class, new Long(movieId));
    em.detach(movie);
    return movie;
}

ただし、エンティティへの参照だけが必要な場合は、代わりにgetReference()メソッドを使用できます。 実際には、プロキシをエンティティに返します。

Movie movieRef = em.getReference(Movie.class, new Long(movieId));

5.3. エンティティの切り離し

永続コンテキストからエンティティをデタッチする必要がある場合は、 detach()メソッドを使用できます。 デタッチするオブジェクトをパラメーターとしてメソッドに渡します。

em.detach(movie);

エンティティが永続コンテキストから切り離されると、切り離された状態になります。

5.4. エンティティのマージ

実際には、多くのアプリケーションでは、複数のトランザクションにわたるエンティティの変更が必要です。 たとえば、UIにレンダリングするために、1つのトランザクションでエンティティを取得したい場合があります。 次に、別のトランザクションがUIで行われた変更をもたらします。

このような状況では、 merge()メソッドを利用できます。 マージメソッドは、デタッチされたエンティティに加えられた変更を管理対象エンティティに取り込むのに役立ちます:

public void mergeMovie() {
    EntityManager em = getEntityManager();
    Movie movie = getMovie(1L);
    em.detach(movie);
    movie.setLanguage("Italian");
    em.getTransaction().begin();
    em.merge(movie);
    em.getTransaction().commit();
}

5.5. エンティティのクエリ

さらに、JPQLを使用してエンティティを照会できます。 getResultList()を呼び出して実行します。

もちろん、クエリが単一のオブジェクトのみを返す場合は、 getSingleResult()を使用できます。

public List<?> queryForMovies() {
    EntityManager em = getEntityManager();
    List<?> movies = em.createQuery("SELECT movie from Movie movie where movie.language = ?1")
      .setParameter(1, "English")
      .getResultList();
    return movies;
}

5.6. エンティティの削除

さらに、 remove()メソッドを使用して、データベースからエンティティを削除できます。 オブジェクトは切り離されていないが、削除されていることに注意することが重要です。

ここで、エンティティの状態は永続から新規に変わります。

public void removeMovie() {
    EntityManager em = HibernateOperations.getEntityManager();
    em.getTransaction().begin();
    Movie movie = em.find(Movie.class, new Long(1L));
    em.remove(movie);
    em.getTransaction().commit();
}

6. 結論

この記事では、HibernateのEntityManagerについて説明しました。 タイプと構成を確認し、永続コンテキストを操作するためにAPIで使用できるさまざまなメソッドについて学習しました。

いつものように、この記事で使用されているコードは、Githubから入手できます。