LoginSignup
11
6

More than 1 year has passed since last update.

MyBatis + Spring boot

Last updated at Posted at 2021-12-09

Mybatis

元々O/RマッパーはJDBC使っていたが
研修が終えてMybatisを使い始めたため、備忘録として記載してます。
初投稿ですので見辛いところも有りますがそこはお許しください。

Gradleの設定

build.graidle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'mysql:mysql-connector-java'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

4行目にMyBatisを宣言

aplication.properties

aplication.properties
spring.datasource.url=jdbc:mysql://localhost:3306/student
spring.datasource.username=root
spring.datasource.password=root8080
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis.configuration.map-underscore-to-camel-case=true

1〜4行目はMySQLの設定

mybatis.configuration.map-underscore-to-camel-case=true はSQLのカラムをキャメルケースに直してくれる便利なライブラリです。

Mapper

UserMapper.java
package com.example.repository;

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.example.domain.User;


@Mapper
public interface UserMapper {

    public void insert(User user);

    public List<User> findByUsers();

    public User findByOne(Integer id);

    public void updateUser(User user);

    public void deleteUser(Integer id);

}

RepositoryではなくMapperで作成
またインターフェイスで作成します。

必須 @Mapperは必ず記載

これがないとMyBatisが動いてくれません。

INSERT

UserMapper.java
public void insert(User user);

SELECT全件

UserMapper.java
public List<User> findByUsers();

SELECT1件

UserMapper.java
public User findByOne(Integer id);

UPDATE

UserMapper.java
public void updateUser(User user);

DELETE

UserMapper.java
public void deleteUser(Integer id);

domain

User.java
package com.example.domain;

import lombok.Data;

@Data
public class User {

    private Integer id;
    private String name;
    private Integer depId;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getDepId() {
        return depId;
    }
    public void setDepId(Integer depId) {
        this.depId = depId;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", depId=" + depId  "]";
    }
}

lombokの@Dataがあればgetterとsetterを書く必要はなし
でも今回は練習用として記載してます。

ControllerとServiceは省きます。

.xml

UserMapper.xml
<?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="com.example.repository.UserMapper">

    <resultMap type="com.example.domain.User" id="userMap">
        <id column="u_id" property="id"/>
        <result column="u_name" property="name"/>
        <result column="u_dep_id" property="depId"/>
        <association property="department" resultMap="departmentMap"></association>
    </resultMap>

    <resultMap type="com.example.domain.Department" id="departmentMap">
        <result column="dep_id" property="id"></result>
        <result column="dep_name" property="name"></result>
    </resultMap>

    <insert id="insert">
        insert into users(name, dep_id) values(#{name},#{depId})
    </insert>

    <select id="findByUsers" resultType="com.example.domain.User">
        select * from users;
    </select>

    <update id="updateUser">
        update users set name = #{name}, dep_id = #{depId} where id = #{id}
    </update>

    <delete id="deleteUser">
        delete from users where id = #{id};
    </delete>

</mapper>

MyBatisの場合SQL文はxmlファイルに書くことができます。
この場合xmlファイルを格納する先はsrc/main/resources/内にUserMapper.javaと同じパス先を用意する必要が有ります。

####src/main/java/com/example/repository/UserMapper.java ####src/main/resources/com/example/repository/UserMapper.xml ↑のようにパス先を揃えるとMyBatis側が自動でresources内で探してくれます

また別のパス先を指定したい場合はproperties(又はyml)内に

mybatis.mapper-locations=classpath*:/パス指定先/*.xml

を指定してあげれば動きます。

INSERT

UserMapper.xml
<insert id="insert">
        insert into users(name, dep_id) values(#{name},#{depId})
</insert>

#UserMapper.java
        public void insert(User user);

タグ内のidはUserMapper.java内のinsertメゾットと同じにする必要があります
また渡ってきたパラメーターは#{プロパティ名}と書く必要があります

SELECT, UPDATE, DELETE

UserMapper.xml
<select id="findByUsers" resultType="com.example.domain.User">
        select * from users;
</select>
<update id="updateUser">
        update users set name = #{name}, dep_id = #{depId} where id = #{id}
</update>

<delete id="deleteUser">
        delete from users where id = #{id};
</delete>

UPDATE, DELETEも同様です。

SELECTのみresultTypeを書き加え、中身には参照するdomain先のパスを指定します。

1対1のテーブル結合

次は1対1のテーブル結合についてです
今回はusersとdepartmentsを結合させます

domain

User.java
package com.example.domain;

import lombok.Data;

@Data
public class User {

    private Integer id;
    private String name;
    private Integer depId;
    private Department department; //departmentオブジェクトを保つために必要

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getDepId() {
        return depId;
    }
    public void setDepId(Integer depId) {
        this.depId = depId;
    }
    public Department getDepartment() {
        return department;
    }
    public void setDepartments(Department department) {
        this.department = department;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", depId=" + depId + ", department=" + department + "]";
    }
}
Department.java
package com.example.domain;

import lombok.Data;

@Data
public class Department {

    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Department [id=" + id + ", name=" + name + "]";
    }   
}

.xml

UserMapper.xml
    <resultMap type="com.example.domain.User" id="userMap">
        <id column="u_id" property="id"/>
        <result column="u_name" property="name"/>
        <result column="u_dep_id" property="depId"/>
        <association property="department" resultMap="departmentMap"></association>
    </resultMap>

    <resultMap type="com.example.domain.Department" id="departmentMap">
        <result column="dep_id" property="id"></result>
        <result column="dep_name" property="name"></result>
    </resultMap>

    <select id="findByOne" resultMap="userMap">
        select 
            users.id as u_id, 
            users.name as u_name, 
            users.dep_id as u_dep_id, 
            departments.id as dep_id, 
            departments.name as dep_name 
        from users 
        left join departments ON users.dep_id = departments.id 
        WHERE users.id = #{id}
    </select>

resultMap

resultMapをUserとDepartmentそれぞれ作成し結合を行います。
typeには参照するdomainのパスを指定、idはタグが認識するために記載します。

columnにはselect結果のカラム名を入れ、propertyにはフィールド名を入れる

idとresultの違い。

idタグは設定された値の数だけListに返してくれます。必須とのことなので主にPKをセットするのかと思われます。。。(知識が浅くてすみません)
他のフィールドはresultでセット。

association

associationはそれぞれ作ったresultMapを繋げるために必要です。
propertyにはUser.java内のフィールドのdepartment(変数名)を書き、resultMapにdepartment用のresultMapのid名を書いてあげる。
ここだとdepartmentMapになります。

1対多のテーブル結合

最後に1対多について記載します。
今回新たにArticleテーブルとCommentテーブルを作成しました。

domain

Article.java
package com.example.domain;

import java.util.List;

import lombok.Data;
@Data
public class Article {

    private Integer id;
    private String title;
    private String introduction;
    private List<Comment> commentList;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getIntroduction() {
        return introduction;
    }
    public void setIntroduction(String introduction) {
        this.introduction = introduction;
    }
    public List<Comment> getCommentList() {
        return commentList;
    }
    public void setCommentList(List<Comment> commentList) {
        this.commentList = commentList;
    }
    @Override
    public String toString() {
        return "Article [id=" + id + ", title=" + title + ", introduction=" + introduction + ", commentList=" + commentList + "]";
    }   
}

複数のCommentを持つため、フィールド内にはListでセット

Comment.java
package com.example.domain;

import lombok.Data;

@Data
public class Comment {

    private Integer id;
    private Integer articleId;
    private String comment;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public Integer getArticleId() {
        return articleId;
    }
    public void setArticleId(Integer articleId) {
        this.articleId = articleId;
    }
    public String getComment() {
        return comment;
    }
    public void setComment(String comment) {
        this.comment = comment;
    }
    @Override
    public String toString() {
        return "Comment [id=" + id + ", articleId=" + articleId + ", comment=" + comment + "]";
    }
}

.xml

ArticleMapper.java
<?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="com.example.repository.ArticleMapper">

    <resultMap type="com.example.domain.Article" id="articleMap">
        <id property="id" column="a_id"></id>
        <result property="title" column="a_title"></result>
        <result property="introduction" column="a_introduction"></result>
        <collection property="commentList" ofType="com.example.domain.Comment">
            <result property="id" column="c_id"></result>
            <result property="article_id" column="c_articleId"></result>
            <result property="comment" column="c_comment"></result>
        </collection>
    </resultMap>

    <select id="findByArticle" resultMap="articleMap">
        select
            article.id as a_id, 
            article.title as a_title, 
            article.introduction as a_introduction,
            comments.id as c_id, 
            comments.article_id as c_article_id, 
            comments.comment as c_comment 
        from article left join comments 
        on article.id = comments.article_id
    </select>
</mapper>

collectionを使うことで結合が可能となります。
propertyにはプロパティ名、ofTypeには参照するdomainのパスを指定してあげます。
これで結合が可能となります。

以上がMyBatisの基本的な書き方です。
まだまだ学ぶことが多そうです。

参考記事

Spring解体新書(Amazon)

11
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
6