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

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

```xml: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を選択しても同様の問題が発生する--はず。

```xml: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メソッドから抜け出せないという現象が発生します。

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

```java: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](https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManagerFactory.html)を見ると、次のように記述されています: "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にも通知してやる必要があるようです(´・ω・｀)