この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:4
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: JPAにおけるEntityManagerの取得方法
SEOタイトル: Spring + JPA で EntityManager を取得する方法

この記事の要点
  • Spring + JPA で EntityManager を取得する方法
  • 推奨: @PersistenceContext private EntityManager em; でフィールド注入
  • 代替: @PersistenceUnit EntityManagerFactory emf; から emf.createEntityManager()
  • Spring Data JPA のリポジトリだけで完結する場合は EntityManager を直接触る必要はない
  • 動的クエリ・JPQL の柔軟な実行・ストアドプロシージャ呼び出しのときに EntityManager を使う

EntityManager とは

JPA の EntityManager はエンティティの永続化・検索・更新・削除を司る中核 API です。Spring Data JPA はこの EntityManager を内部で利用してリポジトリメソッドを実装しています。普段はリポジトリ経由で済みますが、複雑なクエリやネイティブ SQL を使う際に直接触ることがあります。

方式1: @PersistenceContext (推奨)

Spring 管理のコンポーネントで使う場合、これがもっとも一般的:

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Repository
public class UserRepositoryImpl implements UserCustomRepository {

    @PersistenceContext
    private EntityManager em;

    public List findActiveUsersByDate(LocalDate date) {
        // JPQL の動的構築
        StringBuilder jpql = new StringBuilder("SELECT u FROM User u WHERE u.active = true");
        if (date != null) {
            jpql.append(" AND u.lastLoginAt >= :date");
        }

        TypedQuery query = em.createQuery(jpql.toString(), User.class);
        if (date != null) {
            query.setParameter("date", date);
        }
        return query.getResultList();
    }
}

方式2: EntityManagerFactory から個別取得

トランザクション境界を手動で制御したい / 非 Spring 管理のコンテキストで使う場合:

@Component
public class BatchService {
    @PersistenceUnit
    private EntityManagerFactory emf;

    public void processBatch() {
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            // ... 処理
            tx.commit();
        } catch (Exception e) {
            tx.rollback();
            throw e;
        } finally {
            em.close();  // ★ 必ず close
        }
    }
}

方式3: Spring Data JPA Custom Repository

Spring Data JPA で「規約メソッドだけでは無理な処理」を追加する標準パターン:

// ① Custom インターフェイス
public interface UserCustomRepository {
    List findByComplexCondition(UserSearchDto dto);
}

// ② 実装クラス(命名規則: 「リポジトリ名」+ "Impl")
@Repository
public class UserCustomRepositoryImpl implements UserCustomRepository {
    @PersistenceContext
    private EntityManager em;

    @Override
    public List findByComplexCondition(UserSearchDto dto) {
        // CriteriaBuilder で型安全なクエリ
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery cq = cb.createQuery(User.class);
        Root root = cq.from(User.class);
        List predicates = new ArrayList<>();

        if (dto.getName() != null) {
            predicates.add(cb.like(root.get("name"), "%" + dto.getName() + "%"));
        }
        if (dto.getMinAge() != null) {
            predicates.add(cb.ge(root.get("age"), dto.getMinAge()));
        }

        cq.where(cb.and(predicates.toArray(new Predicate[0])));
        return em.createQuery(cq).getResultList();
    }
}

// ③ JpaRepository と一緒に extend する
public interface UserRepository extends JpaRepository, UserCustomRepository {
    // 標準のリポジトリメソッドと、カスタムメソッド両方が使える
}

EntityManager の主要メソッド

メソッド用途
persist(entity)新規エンティティを永続化(INSERT)
merge(entity)デタッチ状態のエンティティを更新(UPDATE)
remove(entity)削除(DELETE)
find(Class, id)主キーで検索
getReference(Class, id)遅延ロード proxy を取得(実 SQL は属性アクセス時)
flush()永続化コンテキストの変更を DB に反映
clear()永続化コンテキストを空に
refresh(entity)DB から再取得して上書き
createQuery(jpql)JPQL クエリ作成
createNativeQuery(sql)ネイティブ SQL クエリ作成
createStoredProcedureQuery(name)ストアドプロシージャ呼び出し

ネイティブ SQL の実行

// 結果を Map で取得
List> rows = em
    .createNativeQuery("SELECT user_id, name, age FROM users WHERE age > ?")
    .setParameter(1, 18)
    .unwrap(NativeQueryImpl.class)
    .setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE)
    .getResultList();

// 結果を Entity にマップ
List users = em
    .createNativeQuery("SELECT * FROM users WHERE age > ?", User.class)
    .setParameter(1, 18)
    .getResultList();

// スカラー値(1 列だけ)
Long count = ((Number) em
    .createNativeQuery("SELECT COUNT(*) FROM users")
    .getSingleResult())
    .longValue();

flush と commit の違い

  • flush(): 永続化コンテキストの変更を DB に送信(INSERT/UPDATE 文の実行)。まだコミットされていない
  • commit(): トランザクションを確定(DB レベルで永続化)
  • Spring の @Transactional はメソッド終了時に自動的に flush + commit
  • 長い処理の途中で DB へ反映確認したいときに em.flush() を明示

パフォーマンス Tip: バッチ INSERT

@Transactional
public void bulkInsert(List users) {
    for (int i = 0; i < users.size(); i++) {
        em.persist(users.get(i));
        if (i % 50 == 0) {  // 50 件ごとに flush + clear
            em.flush();
            em.clear();  // ★ 永続化コンテキストをクリアしてメモリ節約
        }
    }
}

// application.properties で JDBC バッチサイズも設定
// spring.jpa.properties.hibernate.jdbc.batch_size=50
// spring.jpa.properties.hibernate.order_inserts=true
// spring.jpa.properties.hibernate.order_updates=true

関連

  • @Transactional の必要性: EntityManager で更新系を実行する場合、Service 層または同メソッドに @Transactional 必須
  • QueryDSL / Criteria API: 型安全な動的クエリ構築には QueryDSL を導入する選択肢も
  • JPA Specifications: Spring Data JPA 標準の動的クエリ構築機構(CriteriaBuilder ベース)
  • テスト: @DataJpaTest で EntityManager 込みのテストが可能