2021年4月27日火曜日

O/Rマッピングをどうするか決める

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マッピングも実装、確認できました。

0 件のコメント:

コメントを投稿

適格請求書等保存方式(インボイス制度)と消費税の端数処理

消費税の税額計算は 売上税額-仕入れ税額=納税額 2023年10月以降、この納税額の計算の元になる請求書は適格請求書(インボイス)の保存が必要となる。 2019年10月から消費税が10%に引き上げられる際に、日用品等は8%に据え置かれ複数税率を扱う事業者が発生する。 この軽減税率...