Javaプログラムからデータベースへアクセスし、ObjectとRDBのマッピングをするO/Rマッピング。
いくつかの選択肢がありますが、今回はSQLの記述が可能で、チューニングもしやすいといいう理由からMyBatisを採用します。
今回のタスク
- MyBatisのライブラリをダウンロード
- アクセスするデータベースのJDBCドライバを準備します
- mybatis-config.xmlを準備
- データアクセスクラスを準備する
- javaマッピングインターフェースクラスとSQLを記述するxmlを準備する
- データ構造をJavaオブジェクトで表すentityクラスを準備する
- servletを実行するOSはWindowsとする
それでは始めましょう
まずはMyBatisのライブラリをダウンロードします
https://github.com/mybatis/mybatis-3/releasesへアクセスします
執筆時の最新版は3.5.7でしたので、ここからmybatis-3.5.7.zipをダウンロードします
zipの中からMyBatisのライブラリであるmybatis-3.5.7.jarを取り出し、クラスパスの通っている場所に格納します
次にアクセスするデータベースのJDBCドライバ準備ですが、こちらは過去の回で紹介したMySQLの「connector/j」使用しますので、ここでは説明を割愛します
ここからMyBatisでO/Rマッピングを実現する手順に入りますが、作成するもの一式を絵で表すとこんな感じ
mybatis-config.xmlです
データベースへの接続情報と、この後説明します、マッピングインターフェースクラスのあるパッケージ(場所)を指定します。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- DB接続設定 -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/javadev?serverTimezone=JST"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- Mapperのパッケージを指定 -->
<package name="db.map" />
</mappers>
</configuration>
データベースアクセスクラスDbAccessorです。SqlSessionFactoryを生成します。MyBatisのサイトにも下記の記載がありますので、シングルトンパターンで実装してみます。
SqlSessionFactory
生成した SqlSessionFactory は、あなたのアプリケーション実行中はそのまま残しておくべきです。 生成した SqlSessionFactory を破棄したり、再度生成する理由はないはずです。 SqlSessionFactory を再生成しない、というのは所謂ベストプラクティスで、これを行なっていたら「何かおかしいぞ」と考えるべきです。 したがって、SqlSessionFactory に最適なのはアプリケーションスコープ、ということになります。 これを実現する方法はいくつもあります。 最も簡単なのはシングルトンパターンまたはスタティックシングルトンパターンを使う方法です。
MyBatis – MyBatis 3 | スタートガイド から引用
package db;
import java.io.IOException;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class DbAccessor {
private static SqlSessionFactory factory;
static {
try {
String resource = "db/mybatis-config.xml";
// シングルトンとして利用
if (factory == null) {
Reader reader = Resources.getResourceAsReader(resource);
// 読み込んだ設定ファイルからSqlSessionFactoryを生成します
factory = new SqlSessionFactoryBuilder().build(reader);
}
} catch (IOException e) {
throw new ExceptionInInitializerError(e);
}
}
public static SqlSessionFactory getSqlSessionInstance() {
return factory;
}
}
マッピングインターフェースTable001クラスです。今回はListで複数件取得するメソッドとPKで1件取得。更新系としてinsertするものを準備します。
package db.map;
import java.util.List;
import db.entity.Table001Entity;
public interface Table001 {
/*
* 全件取得
*/
List<Table001Entity> selectUsers();
/*
* PKで1件取得
*/
Table001Entity selectUsersPrimary(int id);
/*
* Insert
*/
int insertUser(Table001Entity table001Entity);
}
マッピングインターフェースTable001クラスに対応するSQLを準備します。ここでSQLを記述します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="db.map.Table001" >
<select id="selectUsers" resultType="db.entity.Table001Entity">
<![CDATA[
select
id, name, address
from
table001
]]>
</select>
<select id="selectUsersPrimary" resultType="db.entity.Table001Entity">
<![CDATA[
select
id, name, address
from
table001
where
id = #{id}
]]>
</select>
<insert id="insertUser" parameterType="db.entity.Table001Entity">
<![CDATA[
insert into table001
(id, name, address)
values
(#{id}, #{name}, #{address})
]]>
</insert>
</mapper>
データ構造をJavaオブジェクトで表すidとnameとaddresを持つTable001Entityクラスを準備します。ここにSQL結果がマッピング(O/Rマッピング)されます。
package db.entity;
/*
* エンティティクラス
*/
public class Table001Entity {
int id;
String name;
String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
プログラムからの呼び出し部分です。PKで検索、テーブル全件取得(これを返却しています)、1件Insertするメソッドをサンプルとして掲載します。
public List<Table001Entity> search() throws Exception {
List<Table001Entity> result1;
try {
SqlSessionFactory factory = DbAccessor.getSqlSessionInstance();
try (SqlSession session = factory.openSession()) {
//テーブルのMapperを取得します
Table001 map = session.getMapper(Table001.class);
// table001テーブルを検索します
result1 = map.selectUsers();
// table001テーブルを検索します
Table001Entity result2 = map.selectUsersPrimary(1);
Table001Entity result3 = new Table001Entity();
result3.setId(7);
result3.setName("PGM-Ins-Name7");
result3.setAddress("PGM-Ins-Add7");
int result4 = map.insertUser(result3);
session.commit();
}
}catch(Exception e){
throw e;
}finally {
}
return result1;
}
以上、無事O/Rマッピングも実装、確認できました。