JavaにおけるDB操作（その２）


[この記事](https://qiita.com/zaburo/private/b8c2ab8db7b972d614e7)の続き。
長くなるので分けました。Hibernate(JPA)による操作。とりあえずは動いたがいまいち構成や依存関係がわからない。

## 事前知識（段取り）

Hibernateを利用する場合、おおよそ下記のものを作ることになるらしい。
Javaの世界は不慣れなので表現とかが間違ってるかもしれない。

* hibernate.cfg.xml（DBの接続情報やクラスのマッピング等を指定）
* Modelクラス（DBテーブルと対応するクラス）
* SessionFactory(Config)クラス（xmlから設定を読み込んで利用できる状態にする？っぽい）
* 実行ファイル（App.java）

## 準備

### テンプレート生成

まずはテンプレートの生成。quickstartで特に問題ない。


```bash
mvn archetype:generate \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DarchetypeVersion=RELEASE \
-DinteractiveMode=false \
-DgroupId=com.hoge \
-DartifactId=hibernate-test
```

```bash
cd hibernate-test
```

### pom.xmlの編集

まずは依存ライブラリの指定。hibernateとmysqlを指定。
最新版については[こちら](https://mvnrepository.com/)で検索。

>以下は抜粋になります。dependenciesに追加します。

```xml:pom.xml（抜粋）

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

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.23</version>
    </dependency>
  
```

## 実装

### Hibernate.cfg.xmlの設定

クラスパスにhibernate.cfg.xmlを作成し、設定する。
ここではresoucesフォルダに作成する。

```bash
mkdir -p src/main/resources
touch src/main/resources/hibernate.cfg.xml
```

記述する。
ここで、DBの接続情報、テーブルの生成条件（hbm2ddl）、マッピングするクラスなどを指定する。

```xml:hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>

        <property name="connection.url">jdbc:mysql://localhost:3306/testdb</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

        <!-- 'show_sql' set true to check sql statements on console else set to false -->
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <!-- 新規に作る場合はcreate, そうでない場合はupdate -->
        <property name="hbm2ddl.auto">update</property>

        <!-- JDBC connection pool -->
        <property name="connection.pool_size">5</property>
        <property name="current_session_context_class">thread</property>

        <!-- マップするモデルを記述 -->
        <mapping class="com.hoge.User" />

    </session-factory>
</hibernate-configuration>
```

### Model(Entity)

id,name,ageの3つのプロパティしか持たないが、getterやsetterが必要なので冗長。lombokってのを使うと省略できるらしいが、とりあえず書く。アノテーションでテーブル生成、マッピングの際の条件を表現するみたい。

```java:src/main/java/com/hoge/User.java
package com.hoge;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Column;

@Entity(name = "User")
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) //AUTOだと既存テーブルだとIDがかぶる
    @Column(name = "id")
    private int id;

    @Column(name = "name", length = 32, nullable = true)
    private String name;

    @Column(name = "age")
    private int age;

    // getter, setter

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    public void setAage(int age) {
        this.age = age;
    }

}
```

### SessionFactory(Config)

SessionFactoryを戻すクラスを実装。読み込んだconfig情報をベースにsessionを生成し戻すみたい。
C#のコンテクストて感じかな？

```java:src/main/java/com/hoge/UserSessionFactory.java
package com.hoge;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class UserSessionFactory {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            return new Configuration().configure().buildSessionFactory();
        } catch (Throwable e) {
            System.err.println("build SeesionFactory failed :" + e);
            throw new ExceptionInInitializerError(e);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void close() {
        // Close all cached and active connection pools
        getSessionFactory().close();
    }
}
```

### 実行ファイル

実行ファイル内でいろいろ利用。

```java:src/main/java/com/hoge/App.java
package com.hoge;

import java.util.List;
import org.hibernate.Session;
import org.hibernate.query.Query;

public class App {
    public static void main(String[] args) {
        // session
        Session session = UserSessionFactory.getSessionFactory().openSession();

        // insert
        session.beginTransaction();
        User user = new User();
        user.setName("Bar");
        user.setAage(11);
        session.save(user);
        session.getTransaction().commit();

        // select
        Query<User> query = session.createQuery("From User", User.class);
        List<User> results = query.list();
        System.out.println("number of users:" + results.size());

        for (User u : results) {
            System.out.println("User:" + u + " " + u.getName());
        }

    }
}
```

## 実行

vscodeのjava extensionの実行を利用しているが、下記ので実行可能。

```bash
mvn -q compile exec:java -Dexec.mainClass=com.hoge.App
```

実行するたびにユーザーが増えます。

```bash
User:com.hoge.User@60c97466 hoge
User:com.hoge.User@1e0e9702 foo
User:com.hoge.User@50b06f2c Bar
User:com.hoge.User@1f5b2c0c Bar
User:com.hoge.User@57a06b99 Bar
User:com.hoge.User@30bd1fba Bar
```

うーん。まあ雰囲気はわかったかな。


## 参考

* https://javabydeveloper.com/hibernate-5-example-with-different-configurations/
* https://www.baeldung.com/java-connect-mysql