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へアクセスします
<?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マッピングも実装、確認できました。