1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Spring入門】第6章 MyBatis 入門① データのクラス

1
Last updated at Posted at 2026-10-22

第3章で作った社員テーブルと部署テーブルを、Java のプログラムから扱えるようにする準備として、テーブルの1行分のデータを入れるクラスを作ります。この章では、SQL を自分で書いてデータベースを扱う MyBatis の考え方と、テーブルとクラスの対応のさせ方を学びます。SQL を書いてデータを取り出すのは第7章です。

【知識メモ】この章は MyBatis コースです

第6章と第7章は、JPA コースと MyBatis コースに分かれています。どちらか一方だけを読めば、第8章以降に進めます。JPA コースで進める場合は、第6章 JPA 入門① Entity を読んでください。

この章で学ぶこと

  • MyBatis の考え方(SQL は自分で書き、結果を Java のオブジェクトに入れてもらう)
  • テーブルの1行分のデータを入れるクラスの作り方
  • 社員と部署の関係(多対一)を、Department 型のフィールドで表す方法

6.1 MyBatis とは

データベースのデータを操作するには SQL を使います。第3章では、SQL Developer で SELECT や INSERT を実行しました。

Java のプログラムから SQL を実行することもできますが、「SQL を文字列で組み立てる」「実行結果を1列ずつ取り出して Java のオブジェクトに詰め替える」といった手間のかかる処理が必要になります。

そこで使われるのが MyBatis(マイバティス)です。MyBatis では、SQL は自分で書き、その SQL の実行と、結果を Java のオブジェクトに詰め替える処理を MyBatis が行います。SQL は Java のコードとは別の XML ファイルに書くので、Java のコードの中に SQL の文字列が混ざりません。

テーブルとクラスの対応

MyBatis でも、データベースのテーブルと Java のクラスを、次のように対応させて考えます。

データベース Java この教材の例
テーブル クラス EMPLOYEE テーブル ↔ Employee クラス
行(1件のデータ) オブジェクト(インスタンス) 雷禅 海皇さんの行 ↔ Employee オブジェクト1つ
列 フィールド NAME 列 ↔ name フィールド

ch06-mybatis-1.png

図6-1 SQL の結果とオブジェクトの対応

JPA との違い

Spring でデータベースを扱う方法には、MyBatis のほかに JPA があります(この教材の JPA コースで使っているものです)。どちらも現場で広く使われています。

MyBatis JPA
SQL 自分で書く(XML ファイル) メソッド名などから自動で作られる
データのクラス 普通のクラス(アノテーションは付けない) @Entity などのアノテーションを付ける
結合(JOIN) 結合の SQL を書き、結果の入れ方を XML に書く @ManyToOne などを付けると自動で結合される
向いている場面 実行する SQL を細かく決めたいとき。SQL を読み書きできる人が多い現場 決まった形の検索・登録・変更・削除が多いとき

MyBatis では、実行される SQL が XML ファイルにそのまま書いてあるので、何が実行されるかを読んで確かめられます。DB入門などで学んだ SQL の知識が、そのまま生かせます。

MyBatis と MyBatis Spring Boot Starter の関係

この章では、似た名前の部品がいくつか登場します。関係を整理しておきましょう。

名前 説明
MyBatis SQL を実行し、結果を Java のオブジェクトに詰め替えるライブラリ
MyBatis-Spring MyBatis を Spring フレームワークで使えるようにするライブラリ
MyBatis Spring Boot Starter 上の2つを Spring Boot で最小限の設定で使えるようにしたもの。第4章で pom.xml に書き足した mybatis-spring-boot-starter がこれ

私たちが直接書くのは、データを入れるクラス(この章)、SQL を呼び出すためのインターフェース、SQL を書いた XML ファイル(第7章)の3つです。

6.2 データのクラスを作る

テーブルの1行分のデータを入れるクラスを作ります。部署テーブル用の Department と、社員テーブル用の Employee の2つです。この教材では、これらのクラスを entity パッケージに置きます(JPA コースと同じ名前にしているので、第8章以降のコードは、どちらのコースでもほとんど同じになります)。

まず、第1章・第3章で確認したテーブルの定義をもう一度見ておきましょう。

テーブル 列名 型 Java のフィールド Java の型
DEPARTMENT DEPT_ID NUMBER(4) deptId Integer
DEPT_NAME VARCHAR2(20 CHAR) deptName String
EMPLOYEE EMP_ID NUMBER(6) empId Integer
NAME VARCHAR2(20 CHAR) name String
GENDER NUMBER(1) gender Integer
AGE NUMBER(3) age Integer
BIRTH_DATE DATE birthDate Date
DEPT_ID NUMBER(4) department Department
ADDRESS VARCHAR2(10 CHAR) address String

【知識メモ】名前の付け方のルール

データベースの列名は大文字とアンダースコア(DEPT_ID)、Java のフィールド名は先頭が小文字で単語の区切りを大文字にする書き方(deptId)にするのが一般的です。後者をキャメルケースといいます。

entity パッケージを作る

  1. パッケージ・エクスプローラーで employee-app の src/main/java の中にある、起点となる com.example.employeeapp パッケージを右クリックします。

  2. 新規 → パッケージ を選びます。

    com.example.employeeapp を右クリックして新規→パッケージ

    図6-2 起点のパッケージを右クリック → 新規 → パッケージ

  3. 「名前」には、右クリックした com.example.employeeapp が最初から入っています。末尾に .entity を付け足して com.example.employeeapp.entity にし、完了 をクリックします。

    新規 Java パッケージ(com.example.employeeapp.entity)

    図6-3 名前を com.example.employeeapp.entity にして「完了」

【ご注意】パッケージの場所に注意

第7章で作る Mapper(SQL を呼び出すためのインターフェース)は、必ず com.example.employeeapp パッケージの 中(com.example.employeeapp.○○)に作ってください。Spring Boot は、メインクラス EmployeeAppApplication があるパッケージとその下のパッケージだけを探します(第5章の「コンポーネントスキャン」で学んだ範囲です)。外に作ると、Spring に見つけてもらえずエラーになります。この章で作るデータのクラスは探す対象ではありませんが、この教材では JPA コースと同じ entity パッケージに置きます。

Department クラスを作る

  1. 作成した com.example.employeeapp.entity パッケージを右クリックし、新規 → クラス を選びます。

    entity パッケージを右クリックして新規→クラス

    図6-4 entity パッケージを右クリック → 新規 → クラス

  2. 「パッケージ」に com.example.employeeapp.entity が自動で入っていることを確認し、「名前」に Department と入力して 完了 をクリックします。

    新規 Java クラス(Department)

    図6-5 パッケージを確認し、名前に Department と入力

  3. エディターが開くので、次のようにフィールドを入力します(getter と setter はまだ書きません)。クラス名は、第4章で説明した 補完(Ctrl + Space)を使って入力します。

src/main/java/com/example/employeeapp/entity/Department.java(入力途中)
package com.example.employeeapp.entity;

public class Department {

    /** 部署ID */
    private Integer deptId;

    /** 部署名 */
    private String deptName;

}

フィールドを入力した Department

図6-6 フィールドを入力したところ(赤枠の行にカーソルを置いて、次の getter と setter の生成に進む)

フィールド名に黄色の波線が表示されますが、これは「このフィールドはまだ使われていない」という警告で、この後 getter と setter を作ると消えます。

【再確認】クラス名は、必ず補完(Ctrl + Space)で入力する

第4章の「入力は補完で行う」と同じです。この章では、次の2点に気を付けてください。

  • import 文が必要なクラス名(Date など)は、Date のように途中まで打って Ctrl + Space で補完します。補完で選ぶと、必要な import 文がファイルの先頭に自動で追加されます。
  • 手で全部打ち込むと import 文が追加されず、赤い波線(エラー)になります。そのときは、打った語の末尾にカーソルを置いて Ctrl + Space を押し、候補から選び直してください。

getter と setter を自動生成する

フィールドは private なので、Controller や画面から値を読み書きするための getter と setter が必要です。Eclipse の機能で自動生成しましょう。

  1. エディターの中で、最後の } の直前の空行(図6-6 の赤枠の行)にカーソルを置きます。

  2. メニューの ソース → getter および setter の生成 を選びます(エディター内で右クリックしても同じメニューがあります)。

    ソース→getter および setter の生成

    図6-7 ソース → getter および setter の生成

  3. 表示された画面で すべて選択 をクリックし、deptId と deptName にチェックが入ったことを確認します。

  4. 生成 をクリックします。

    getter および setter の生成画面ですべて選択

    図6-8 すべて選択 → チェックを確認 → 生成

  5. Ctrl + S で保存します。エディターのタブの「*」(未保存のしるし)が消えたことを確認しましょう。

    保存前と保存後のタブの比較

    図6-9 getter と setter を生成した直後(上)と、保存したあと(下)

Eclipse でよく使う操作は、付録C「プロジェクトとファイルの操作」 にまとめています。

完成した Department クラスは次のとおりです。

src/main/java/com/example/employeeapp/entity/Department.java(完成)
package com.example.employeeapp.entity;

public class Department {

    /** 部署ID */
    private Integer deptId;

    /** 部署名 */
    private String deptName;

    public Integer getDeptId() {
        return deptId;
    }

    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }

    public String getDeptName() {
        return deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

}

Employee クラスを作る

同じ手順で、com.example.employeeapp.entity パッケージを右クリックして Employee クラスを作り、次のように入力します。

src/main/java/com/example/employeeapp/entity/Employee.java(入力途中)
package com.example.employeeapp.entity;

import java.util.Date;

public class Employee {

    /** 社員ID */
    private Integer empId;

    /** 氏名 */
    private String name;

    /** 性別(1:男、2:女) */
    private Integer gender;

    /** 年齢 */
    private Integer age;

    /** 生年月日 */
    private Date birthDate;

    /** 部署 */
    private Department department;

    /** 住所(都道府県) */
    private String address;

}

Employee のフィールド

図6-10 フィールドを入力したところ(赤枠の行にカーソルを置いて、getter と setter を生成する)

【ご注意】Date は java.util.Date を選ぶ

Date を補完すると、候補に Date - java.sql など同じ名前のクラスも並びます。必ず Date - java.util を選んでください。

続けて、Department と同じ手順で getter と setter を自動生成します。

  1. エディターの中で、最後の } の直前の空行(図6-10 の赤枠の行)にカーソルを置きます。

  2. メニューの ソース → getter および setter の生成 を選びます。

  3. 表示された画面で すべて選択 をクリックし、7つのフィールドすべてにチェックが入ったことを確認します。

  4. 生成 をクリックします。

  5. Ctrl + S で保存し、エディターのタブの「*」が消えたことを確認します。

    Employee の自動生成した getter と setter

    図6-11 Employee クラス(自動生成した getter と setter の部分)

完成した Employee クラスは次のとおりです。

src/main/java/com/example/employeeapp/entity/Employee.java(完成)
package com.example.employeeapp.entity;

import java.util.Date;

public class Employee {

    /** 社員ID */
    private Integer empId;

    /** 氏名 */
    private String name;

    /** 性別(1:男、2:女) */
    private Integer gender;

    /** 年齢 */
    private Integer age;

    /** 生年月日 */
    private Date birthDate;

    /** 部署 */
    private Department department;

    /** 住所(都道府県) */
    private String address;

    public Integer getEmpId() {
        return empId;
    }

    public void setEmpId(Integer empId) {
        this.empId = empId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getGender() {
        return gender;
    }

    public void setGender(Integer gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

}

6.3 データのクラスの解説

アノテーションを付けない

MyBatis のデータのクラスには、アノテーションを付けません。フィールドと getter・setter だけの、普通のクラスです。

「どのテーブルから、どの列を取り出すか」は、第7章で XML に書く SQL で決めます。MyBatis は、その SQL の結果の列を、名前が対応するフィールドに入れます。そのため、データのクラスの側には、テーブルの情報を書く必要がありません。

列とフィールドの対応

SQL の結果の列名は BIRTH_DATE、フィールド名は birthDate のように、書き方が違います。MyBatis は、第4章で application.properties に書いた次の設定によって、アンダースコアの区切りを大文字の区切りに読み替えて対応させます。

application.properties(第4章で書いたもの。抜粋)
mybatis.configuration.map-underscore-to-camel-case=true
SQL の結果の列名 入るフィールド
DEPT_ID deptId
DEPT_NAME deptName
BIRTH_DATE birthDate
NAME name

そのため、フィールド名は、列名と対応するように付けます。対応する名前のフィールドが無い列は、どのフィールドにも入りません(エラーにはならず、フィールドは null のままになります)。

部署の department フィールドだけは、名前で対応させることができません。後の「社員と部署の関係」で説明します。

主キーの番号(シーケンス)

第3章では、主キーの番号を払い出すシーケンスを作りました。

第3章の CREATE SEQUENCE(抜粋)
CREATE SEQUENCE SEQ_EMP NOCACHE;

MyBatis では、このシーケンスの使い方も SQL に書きます。社員を登録する SQL で SEQ_EMP.NEXTVAL から次の番号を取り出し、その番号を社員IDにして INSERT します(第7章で書きます)。データのクラスの側に書くことはありません。

なぜ int ではなく Integer を使うのか

ID や年齢のフィールドには、int ではなく Integer を使っています。int は必ず何かの数値(初期値は 0)を持ちますが、Integer は 「値がない」ことを null で表せる からです。

たとえば新規登録する前の社員には、まだ社員IDがありません。このとき int だと 0 になってしまい、「社員IDが 0 の社員」なのか「まだ ID がない社員」なのか区別できません。データのクラスでは、数値のフィールドに Integer などのラッパークラスを使うのが基本です。

日付は Date

Oracle の DATE 型の列(生年月日)は、Java の java.util.Date 型のフィールドに対応させます。java.util.Date は日付と時刻を表すクラスで、現場のシステムで広く使われています。生年月日のように日付だけを扱う場合、時刻の部分は 0時0分0秒 になります。変換は MyBatis が自動で行います。なお、新しく作るシステムでは、日付だけを表す java.time.LocalDate を使うことも増えています。

社員と部署の関係

社員は必ずどこか1つの部署に所属します。一方、1つの部署には複数の社員が所属できます。このように「社員(多)が部署(一)に属する」関係を 多対一 といいます。

ch06-mybatis-2.png

図6-12 社員と部署は「多対一」の関係

テーブルでは、社員テーブルの DEPT_ID 列に部署IDの数値が入っているだけでした。部署名を知るには、SQL で部署テーブルと 結合(JOIN) する必要があります。

SQL で社員と部署名を取り出す場合
SELECT e.EMP_ID, e.NAME, d.DEPT_NAME
  FROM EMPLOYEE e
  JOIN DEPARTMENT d ON e.DEPT_ID = d.DEPT_ID;

Employee クラスでは、部署IDの数値(Integer deptId)ではなく、Department オブジェクトそのもの をフィールドに持たせました。

Employee.java(抜粋)
/** 部署 */
private Department department;

第7章では、社員テーブルと部署テーブルを結合する SQL を書き、その結果のうち部署の列(DEPT_ID・DEPT_NAME)を Department オブジェクトに入れて、department フィールドにセットするよう MyBatis に指定します。この指定は名前の対応だけではできないので、XML に書きます。

こうしておくと、Java のプログラムでは次のように書くだけで部署名が取れます。

Employee を使う側のコード(例)
String deptName = employee.getDepartment().getDeptName();   // "営業部"

ch06-mybatis-3.png

図6-13 Employee オブジェクトが Department オブジェクトを持っている

【知識メモ】部署IDはどうやって取り出す?

社員の部署IDが必要なときは、employee.getDepartment().getDeptId() と書きます。第7章の登録・変更の SQL でも、この形で部署IDを取り出して DEPT_ID 列に入れます。

6.4 よくあるエラー

データのクラスの書き間違いは、この章の時点ではエラーになりません。第7章のテストや、第8章以降でアプリを起動したときに、次のような形で現れます。そのときは、次の表を参考に直してください。

起きること 主な原因 対処
画面の一部の項目(生年月日など)が空になる 列の値がフィールドに入っていない フィールド名が列名と対応しているか(BIRTH_DATE → birthDate)、application.properties に mybatis.configuration.map-underscore-to-camel-case=true があるかを確認する
生年月日を使うところでエラーになる Date の import を間違えた import 文が java.util.Date になっているかを確認する(java.sql.Date ではない)
赤い波線(コンパイルエラー) import 文が無い、つづりの間違い 赤い波線の語の末尾にカーソルを置いて Ctrl + Space を押し、候補から選び直す

その他のエラーは、付録B「部品(Bean)やクラスが見つからない」 も参考にしてください。

6.5 まとめと確認問題

まとめ

  • MyBatis では、SQL は自分で書き、SQL の実行と、結果を Java のオブジェクトに詰め替える処理を MyBatis が行う
  • テーブルの1行分のデータを入れるクラスは、フィールドと getter・setter だけの普通のクラスにする。アノテーションは付けない
  • SQL の結果の列は、名前が対応するフィールドに入る(BIRTH_DATE → birthDate)。読み替えは application.properties の map-underscore-to-camel-case の設定で行う
  • 主キーの番号は、登録の SQL の中で第3章のシーケンスから取り出す(第7章)
  • 社員と部署のような多対一の関係は、Department 型のフィールドで表す。結合した結果の入れ方は第7章で XML に書き、employee.getDepartment().getDeptName() で部署名が取れるようにする

確認問題

問1 MyBatis と JPA の、SQL の扱い方の違いを説明してください。

解答を見る

MyBatis では SQL を自分で書き(XML ファイル)、SQL の実行と結果の詰め替えを MyBatis が行います。JPA では、SQL はメソッド名などから自動で作られ、自分で書く必要がありません。

問2 データのクラスの ID のフィールドに、int ではなく Integer を使うのはなぜですか。

解答を見る

Integer は「値がない」ことを null で表せるからです。新規登録前の社員のように、まだ ID が決まっていない状態を表すことができます。int では 0 になってしまい、区別がつきません。

問3 SQL の結果の BIRTH_DATE 列の値が、birthDate フィールドに入るのはなぜですか。

解答を見る

application.properties に mybatis.configuration.map-underscore-to-camel-case=true を書いているので、MyBatis がアンダースコアの区切り(BIRTH_DATE)を大文字の区切り(birthDate)に読み替えて、名前が対応するフィールドに値を入れるからです。


前へ

第5章 DI とアプリの構成

次へ

第7章 MyBatis 入門② Mapper と SQL

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?