元営業WEBエンジニアのアプリ開発日記

営業出身のWEB系エンジニアが気になったものから作ってはメモを残してくブログ

MyBatisとSpringBootで素敵にORマッピング

概要

前回SpringBootで簡単なアプリを作成する記事を書いたのでDB(MySQL)との接続も書いとこうかなと思います。
本記事ではERMasterでER図やSQLなどを生成して、flywayでテーブル生成してますが面倒くさかったら直接テーブル作ってもらっても問題ないっす!
EclipseのVersion: Oxygen.1a Release (4.7.1a)

テーブルの作成

DDLの定義

とりあえずAuto_inrementのidとvarcharのnameが存在するmemberテーブルを定義

/* Drop Tables */

DROP TABLE IF EXISTS members;

/* Create Tables */

-- 会員情報一覧テーブル
CREATE TABLE members
(
    -- id
    id int NOT NULL AUTO_INCREMENT COMMENT 'id',
    -- 名前
    name varchar(255) NOT NULL COMMENT '名前',
    -- レコード生成日時
    created_at datetime DEFAULT NOW() NOT NULL COMMENT 'レコード生成日時',
    -- レコード更新日時
    updated_at datetime COMMENT 'レコード更新日時',
    PRIMARY KEY (id)
) COMMENT = '会員情報一覧テーブル';

(参考までに)自分はERMasterを使っているので以下手順で上記DDL生成

  • ERMasterインストール手順に従いEclipseにERMasterをインストール!
  • 新規ER図作成
    • ファイル→新規→その他→ERMaster→次へ→自分のプロジェクト選択→ファイル名適当に入力→次へ→データベースはMySQL→完了
  • ER図の画面でポチポチクリックして必要項目入力
  • DDLファイルを生成
    • プロパティー的なの出してエクスポート→DDL→OK

flywayの導入

pluginsとdependenciesに1行を追加

...
plugins {
    id "org.flywaydb.flyway" version "4.2.0"
}

...

dependencies {
    // Flyway動かすためのconnector
    compile('mysql:mysql-connector-java')
}

以下ファイルを生成し上で記載したmembersのDDLを記載
future/src/main/resources/db/migration/V1.0.0__members.sql
V1.0.0__xxx.sqlはFlywayの書き方でVの数字の順番にファイルを読み込んで実施してくれる

flywayでテーブル作成

データベース作成された状態で以下コマンド実行。
-Dflyway.urlのfutureは各自用意したデータベース名に変えといてください

cd future
./gradlew flywayClean flywayMigrate -Dflyway.url=jdbc:mysql://localhost:3306/future -Dflyway.user=root -Dflyway.password=root

無事テーブル出来てた

docker exec -it mysql01 bash

mysql -u root -p future

mysql> show tables;
+------------------+
| Tables_in_future |
+------------------+
| members          |
| schema_version   |
+------------------+
2 rows in set (0.00 sec)

MybatisとSpringBootの連携

MybatisGeneratorのインストール

Qiitaに書いてた頃の記事にも書いたんですが、Java8から使えるLocalDateTime型に紐付いたMapper, Dtoを生成するには2018/7/4リリースのVersion:1.3.7以上じゃないといけないらしい。
そしてMavenならあるみたいだけどGradle版はまだなさそう。。。。
ということで、公式サイト6番目にあるEclipseを使う方式にする

EclipseMarketPlaceで「mybatis」と検索して「MyBatis Generator 1.3.7」をインストール!!

MybatisGeneratorの設定

以下設定ファイルを作成。
futureとかxyz.ucworkって書いてある部分は自分の環境に合わせて適宜修正ください

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <context id="MySQLTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true" />
        </commentGenerator>
        <jdbcConnection
                driverClass="com.mysql.jdbc.Driver"
                connectionURL="jdbc:mysql://localhost:3306/future"
                userId="root"
                password="root">
                <property name="nullCatalogMeansCurrent" value="true" />
        </jdbcConnection>
        <javaTypeResolver>
            <property name="useJSR310Types" value="true"/>
        </javaTypeResolver>
        <javaModelGenerator
                targetPackage="xyz.ucwork.future.domain.model"
                targetProject="future/src/main/java">
            <property name="enableSubPackages" value="true" />
        </javaModelGenerator>
        <sqlMapGenerator
                targetPackage="xyz.ucwork.future.domain.mapper"
                targetProject="future/src/main/resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <javaClientGenerator
                targetPackage="xyz.ucwork.future.domain.mapper"
                targetProject="future/src/main/java" type="MIXEDMAPPER">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <table schema="future"
               tableName="%"
               enableInsert="true"
               enableSelectByPrimaryKey="true"
               enableSelectByExample="false"
               enableUpdateByPrimaryKey="true"
               enableUpdateByExample="false"
               enableDeleteByPrimaryKey="true"
               enableDeleteByExample="false"
               enableCountByExample="false"
               selectByExampleQueryId="false"
               modelType="flat">
               <property name="useActualColumnNames" value="false"/>
        </table>
    </context>
</generatorConfiguration>

補足で説明

LocalDateTime型で出力するための設定

<javaTypeResolver>
    <property name="useJSR310Types" value="true"/>
</javaTypeResolver>

information_schemaデータベースとかのテーブルのmapper, dtoを出力しないための設定

<property name="nullCatalogMeansCurrent" value="true" />

テーブル全てのmapper, dto生成するための設定

<table schema="future"
               tableName="%"

Eclipseでのエラー対応

org.apache.ibatis が見つかりません的なエラーが出てたんでbuild.gradleに1行追加

dependencies {
  ...
    // Mybatis動かす用
    compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2')
}

Eclipse上でbuild.gradleの内容を反映するには、プロジェクト上で右クリックしてGradle→Gradleプロジェクトのリフレッシュを押すんだけど..Gradleがない!!!

右クリックして構成→Gradleネーチャーの追加を押したらぽんって出てきた!!らっきー!

SpringからMyBatisでDB操作してみる

Spring側の設定

このままだとTomcatへのデプロイ時にエラーが発生するから各種設定が必要
xyz.ucworkfutureは例のごとく自分の環境で置き換えてくださいね

Mybatis用の設定ファイルを準備

<?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>
    <settings>
        <setting name="logImpl" value="LOG4J" />
        <setting name="mapUnderscoreToCamelCase" value="true" />
    </settings>

    <typeAliases>
        <package name="xyz.ucwork.future.domain.model" />
    </typeAliases>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC">
                <property name="" value="" />
            </transactionManager>
            <dataSource type="UNPOOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://mysql01:3306/future" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <package name="xyz.ucwork.future.domain.mapper" />
    </mappers>
</configuration>

Springのapplication.ymlにdatasourceの接続情報記載
※ymlのが好きなのでapplication.propertiesapplication.ymlに書き換えてます

spring:
    datasource:
        url: jdbc:mysql://mysql01:3306/future
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver

ここまで来たらtomcatにデプロイしてもエラー無くいけるはず!!

独自のMapperでINSERTしてSELECT

せっかく自動出力しときながら独自のを作成してinsertとselect

insertとselect用のMybatis独自設定

もう疲れてきた。自分で好きにMapper作る

package xyz.ucwork.future.domain.mapper.ext;

import java.util.List;

import xyz.ucwork.future.domain.model.Members;

/**
 * membersテーブル操作用のmapper.
 * @author uchiyama-shintaro
 *
 */
public interface ExtMembersMapper {

    /**
     * 名前でmembersテーブルに追加.
     * @param members
     * @return
     */
    int insertWithName(Members members);

    /**
     * 名前でレコード検索.
     * @param name
     * @return
     */
    List<Members> selectByName(String name);

}

自分で好きなMapper用xml作る。例のごとくxyz.ucworkとfutureは書き換えてね

<?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="xyz.ucwork.future.domain.mapper.ext.ExtMembersMapper">
    <insert id="insertWithName" parameterType="xyz.ucwork.future.domain.model.Members">
        INSERT INTO members(
          name)
        VALUES(
          #{name}
        );
        <selectKey resultType="int" keyProperty="id" order="AFTER">
          select @@IDENTITY
        </selectKey>
    </insert>

    <resultMap id="BaseResultMap" type="xyz.ucwork.future.domain.model.Members">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="name" jdbcType="VARCHAR" property="name" />
        <result column="created_at" jdbcType="TIMESTAMP" property="createdAt" />
        <result column="updated_at" jdbcType="TIMESTAMP" property="updatedAt" />
    </resultMap>
    <select id="selectByName" resultMap="BaseResultMap">
        SELECT * FROM members WHERE name = #{name}
    </select>
</mapper>

工夫ポイントとしてはinsert後のautoincrementの値をdtoに詰め込まれるようにselect @@IDENTITYを入れたくらいかな

実際に取得してみる

特質ポイント的にはmapper読み込まれるように@MapperScan({"xyz.ucwork.future.domain.mapper"})追加してるとこかな

package xyz.ucwork.future;

import java.util.List;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import xyz.ucwork.future.domain.mapper.MembersMapper;
import xyz.ucwork.future.domain.mapper.ext.ExtMembersMapper;
import xyz.ucwork.future.domain.model.Members;

@SpringBootApplication
@RestController
@MapperScan({"xyz.ucwork.future.domain.mapper"})
public class FutureApplication {
    @Autowired
    private ExtMembersMapper extMembersMapper;
    @Autowired
    private MembersMapper membersMapper;

    public static void main(String[] args) {
        SpringApplication.run(FutureApplication.class, args);
    }

    @RequestMapping("/")
    public String function() {
        // membersテーブルにインサート
        String name = "testName";
        Members insertMembers = new Members();
        insertMembers.setName(name);
        extMembersMapper.insertWithName(insertMembers);

        // idからレコード取得
        Members members1 = membersMapper.selectByPrimaryKey(insertMembers.getId());
        // nameからレコード取得
        List<Members> members2 = extMembersMapper.selectByName(name);

        // 画面に表示
        return "name from id: "+members1.getName()+"  name from name: "+members2.get(0).getName();
    }
}

まとめ

なんだか息切れしてしまった
ちょっとDB操作したいだけなのに大変。絶対忘れちゃうからここにメモを残す