1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JPA(Hibernate)の利用時にmainメソッドの最終行まで行きついても、Javaアプリケーションが終了しない。

Last updated at Posted at 2018-07-23

前提として、Hibernateのversionは5.3.3。pom.xmlのdependenciesは次のようになります。

pom.xml
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-core</artifactId>
  <version>5.3.3.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
  <groupId>javax.xml.bind</groupId>
  <artifactId>jaxb-api</artifactId>
  <version>2.3.0</version>
</dependency>

まず以下のようなMETA-INF\persistence.xmlを準備します。dialectやdriverがDb2になっていますが、ここではRDBMSの種類は問題ではなく、たとえばMySQLやPostgresを選択しても同様の問題が発生する--はず。

persistence.xml
<?xml version="1.0" encoding="UTF-8"?>

<persistence
  xmlns="http://xmlns.jcp.org/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                      http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
  version="2.1">
  <persistence-unit name="app">
    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect" />
      <property name="hibernate.connection.driver_class" value="com.ibm.db2.jcc.DB2Driver" />
      <property name="hibernate.connection.url" value="jdbc:db2://[url]:[port]/[DBNAME]" />
      <property name="hibernate.connection.username" value="[user name]" />
      <property name="hibernate.connection.password" value="[password]" />
      <property name="hibernate.show_sql" value="true" />
    </properties>
  </persistence-unit>
</persistence>

そのあと次のようなmainメソッドを作成&実行したところ、Javaアプリケーションが終了しなくなりました(´・ω・`) たとえばeclipseで「右クリック > Run As > Java Application」と選択し、mainメソッドを実行すると、通常であればその中身を順に実行したあと「terminated」という表示が出現します。しかしこの手順でmainメソッドを実行すると、mainメソッドの最終行までは行きついているようなのですが、いつまでたっても「terminated」という表示が出てきません。あるいは実行可能jarにまとめて、このmainメソッドを実行すると、このプロセスがいつまでたっても終了しません。kill -9などで強制終了をかけない限り、mainメソッドから抜け出せないという現象が発生します。

Main.java
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class Main {
    public static void main(String[] args) {
        EntityManagerFactory factory = null;
        EntityManager manager = null;
        EntityTransaction transaction = null;
        
        try {
            factory = Persistence.createEntityManagerFactory("app");
            manager = factory.createEntityManager();
            transaction = manager.getTransaction();
            
            transaction.begin();            
            // DO SOMETHING: DBへの操作を実施する。
            transaction.commit();
        } catch (RuntimeException e) {
            if (transaction != null && transaction.isActive()) {
                transaction.rollback();
            }
            throw e;
        }
    }
}

__さてこの「mainメソッドの最終行にまで行きついたにも関わらず、アプリケーションが終了しない」問題ですが、EntityManagerFactorycloseすることで解決することができました。__たとえばmainメソッドを以下のように書き換えてやると、mainメソッドの終了とともにeclipseは「terminated」を表示し、実行可能jarはプロセスを完了するようになりました。

Main.java
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class Main {
    public static void main(String[] args) {
        EntityManagerFactory factory = null;
        EntityManager manager = null;
        EntityTransaction transaction = null;
        
        try {
            factory = Persistence.createEntityManagerFactory("app");
            manager = factory.createEntityManager();
            transaction = manager.getTransaction();
            
            transaction.begin();
            // DO SOMETHING: DBへの操作を実施する。
            transaction.commit();
        } catch (RuntimeException e) {
            if (transaction != null && transaction.isActive()) {
                transaction.rollback();
            }
            throw e;
        } finally {
            if (manager != null) {
                manager.close();
            }
            if (factory != null) {
                factory.close();
            }
        }
    }
}

要するにEntityManagerFactoryのクローズ漏れが原因でした。EntityManagerFactoryのJavaDocを見ると、次のように記述されています: "When the application has finished using the entity manager factory, and/or at application shutdown, the application should close the entity manager factory." JavaEEやSpringを利用する場合、@Autowired@Injectなどを利用し、インスタンスの生成をすべてフレームワークにお任せするのが基本ですが、上述の例のようにインスタンスのライフサイクルを自ら制御する場合、アプリケーションの終了とともにEntityManagerFactory#closeを呼び出して、アプリケーションが完了することをJPAにも通知してやる必要があるようです(´・ω・`)

1
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?