LoginSignup
1
3

More than 3 years have passed since last update.

【JavaEE】シングルトンでEntityManagerをDIする方法

Last updated at Posted at 2020-01-23

※ EntityManagerのDIはできますが、データの更新が動きません。原因について調査中。取得と登録は問題ありません。

はじめに

JavaEEをやっていると、EntityManagerを扱うEJB(いわゆるビジネスロジッククラス)は通常ステートレス管理にします。理由としては、EntityManagerがスレッドセーフではないため、トランザクション単位でDIする必要があるためです。Springでいうところの@Service@Repositoryは基本的にシングルトン管理になります。

じゃあ、JavaEEでもシングルトンにしましょう。

なぜシングルトンか

単刀直入に言うと、メモリ節約のためです。ステートレス管理の場合、EJBプールというメモリ領域にEJBのインスタンスが保持されます。必要なときにプールからインスタンスを取得しDIされます。domain.xmlなどのサーバ設定ファイルにEJBのプールサイズなどを設定できますが、これより多いリクエストが発生した際に、新たにインスタンスが作られることになります。インスタンスが生成されるということはそれだけメモリを使うことになります。一方、シングルトンの場合は、アプリケーションで1つしかインスタンスを持ちませんので、メモリの使用を抑えることができます。

NGパターン

EntityManager利用クラス
@Singleton 
public class UserService {

    @PersistenceContext 
    private EntityManager em;

    // 〜以下省略〜
}

スレッドセーフではないEntityManagerをアプリケーションで1つしか持たないようになっています。

OKパターン

EntityManagerを生成する EntityManagerFactory というクラスが存在します。
このクラスはスレッドセーフであるため、シングルトン管理で問題ないのでこれを利用します。

EntityManager生成クラス
@ApplicationScoped
public class EntityManagerFactoryService {
    private static EntityManagerFactory factory;

    public EntityManagerFactory getEntityManagerFactory() {
        if (factory == null) {
            factory = Persistence.createEntityManagerFactory("testUnit");
        }
        return factory;
    }

    @Produces
    @RequestScoped
    public EntityManager getEntityManager() {
        return getEntityManagerFactory().createEntityManager();
    }

    @PreDestroy
    public void destroy() {
        if (factory.isOpen()) {
            factory.close(); // クローズしないと再デプロイ時にエンティティが見つからなくなる。
        }
    }
}
EntityManager利用クラス
@Singleton 
public class UserService {
    @Inject
    private EntityManager em;
}
1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3