MyBatisの基本使用

1. MyBatisのクイックスタート

要件:MyBatisを使用してすべてのユーザーデータを取得する。

1) Spring Bootプロジェクトを作成し、MyBatisの依存関係、MySQLドライバ、Lombokを追加する。

プロジェクト作成後、pom.xmlファイルに自動的にMyBatisとMySQLドライバの依存関係が追加されます。

2) データ準備:ユーザーテーブル(user)を作成し、対応するエンティティクラスUserを作成する。

  • ユーザーテーブル user(既に存在すれば作成不要)
CREATE TABLE user (
    id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT 'ID, 主キー',
    username VARCHAR(20) COMMENT 'ユーザー名',
    password VARCHAR(32) COMMENT 'パスワード',
    name VARCHAR(10) COMMENT '名前',
    age TINYINT UNSIGNED COMMENT '年齢'
) COMMENT 'ユーザーテーブル';

INSERT INTO user(id, username, password, name, age) VALUES (1, 'daqiao', '123456', '大喬', 22),
                                                            (2, 'xiaoqiao', '123456', '小喬', 18),
                                                            (3, 'diaochan', '123456', '貂蝉', 24),
                                                            (4, 'lvbu', '123456', '吕布', 28),
                                                            (5, 'zhaoyun', '12345678', '趙雲', 27);
  • エンティティクラス:エンティティクラスのプロパティ名はテーブルのフィールド名に対応します。エンティティクラスは`com.example.entity`パッケージに配置します。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer id; // ID
    private String username; // ユーザー名
    private String password; // パスワード
    private String name; // 名前
    private Integer age; // 年齢
}

3) MyBatisの設定

`application.properties`でデータベース接続情報を設定します。

# データベースアクセスのURL
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
# データベースドライバクラス名
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# データベースアクセス-ユーザー名
spring.datasource.username=root
# データベースアクセス-パスワード
spring.datasource.password=root@1234

4) MyBatisプログラムの作成:MyBatisの永続層インターフェースを作成し、SQL文を定義する(アノテーションを使用)

作成したSpring Bootプロジェクト内で、ガイドクラスと同じパッケージ(`com.example`)に`mapper`パッケージを作成し、その中に`UserRepository`インターフェースを作成します。

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

@Mapper
public interface UserRepository {
    /**
     * すべて取得
     */
    @Select("SELECT * FROM user")
    List<User> fetchAllUsers();
}
  • @Mapperアノテーション:これはMyBatisのMapperインターフェースであることを示します。
  • @Selectアノテーション:これはSELECTクエリを表し、SELECTクエリ文を記述するために使用します。

5) ユニットテスト

作成したSpring Bootプロジェクト内で、src/testディレクトリに自動的にテストクラスが作成されています。また、このテストクラスにはすでに`@SpringBootTest`アノテーションが付与されており、Spring Bootと統合されていることを示しています。

@SpringBootTest
class MybatisDemoApplicationTests {

    @Autowired
    private UserRepository userRepository;

    @Test
    public void testFetchAllUsers() {
        List<User> users = userRepository.fetchAllUsers();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

テストクラスは、ガイドクラスを介してSpring環境をロードします。テストしたいBeanオブジェクトがあれば、`@Autowired`アノテーションを使用して注入し、テストを行います。

2. 補足設定

2-1) SQLヒントの設定

デフォルトでは、`@Select`アノテーションでSQL文を書くとヒントが表示されません。IDEAでSQL文のヒントを得るには、IDEAでMySQLデータベースへのリンクを設定する必要があります。

設定を完了すると、SQLキーワードにヒントが表示されるようになりますが、まだテーブル名やカラム名が認識されない場合があります。

  • 原因:IDEAとデータベースが接続されていないため、テーブル情報が認識されない
  • 解決策:IDEAでMySQLデータベースへの接続を設定する

2-2) MyBatisログ出力の設定

デフォルトでは、MyBatisでSQL文が実行されたときにログが出力されません。`application.properties`に以下の設定を追加することで、ログを見ることができます。

# MyBatisの設定
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

この設定を有効にすると、ユニットテストを実行した際に、コンソールに実行されたSQL文が出力されます。

3. データベース接続プール

3-1) はじめに

  • データベース接続プールがない場合

クライアントがSQL文を実行するには、新しいコネクションオブジェクトを作成し、SQLを実行した後、コネクションオブジェクトを閉じてリソースを解放する必要があります。これにより、頻繁なコネクションの作成と破棄が行われ、システムのパフォーマンスに影響を与えます。

  • データベース接続プールがある場合

データベース接続プールは、コネクションオブジェクトを管理するためのコンテナです。

  • アプリケーションが起動時に、データベース接続プール(コンテナ)内に指定数のコネクションオブジェクトを作成します。
  • クライアントがSQLを実行する前に、データベース接続プールからコネクションオブジェクトを取得し、SQLを実行します。実行が完了したら、コネクションオブジェクトをプールに戻すことができます。
  • 空き時間が最大空き時間を超えたコネクションオブジェクトは自動的に解放され、リソースの浪費を防ぎます。

データベース接続プールの利点:

  • リソースの再利用
  • システムレスポンスタイムの向上
  • データベース接続の漏れ防止

デフォルトのデータベース接続プールをDruidに切り替えるには、以下の手順を実施します:

  • pom.xmlファイルに依存関係を追加します。
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.19</version>
</dependency>
  • application.propertiesにデータベース接続設定を追加します。
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

設定を完了すると、ユニットテストを再度実行した際に、コンソール出力のログで接続プールがDruidに切り替わっていることが確認できます。

4. CRUD操作

4-1) 削除

  • 要件:IDに基づいてユーザー情報を削除する
  • SQL:DELETE FROM user WHERE id = 5;
  • Mapperインターフェースメソッド:
/**
 * IDに基づいて削除
 */
@Delete("DELETE FROM user WHERE id = #{userId}")
void deleteUserById(@Param("userId") Integer userId);
  • ユニットテストメソッドを追加してテストします。
@Test
public void testDeleteUserById() {
    userRepository.deleteUserById(3);
}

4-2) 追加

  • 要件:ユーザーを追加する
  • SQL:INSERT INTO user(username, password, name, age) VALUES('shunsuke', '123456', '松祐', 25);
  • Mapperインターフェース:
/**
 * ユーザーを追加
 */
@Insert("INSERT INTO user(username, password, name, age) VALUES(#{user.username}, #{user.password}, #{user.name}, #{user.age})")
void addUser(@Param("user") User user);
  • ユニットテスト:
@Test
public void testAddUser() {
    User newUser = new User();
    newUser.setUsername("admin");
    newUser.setPassword("123456");
    newUser.setName("管理者");
    newUser.setAge(30);
    userRepository.addUser(newUser);
}

4-3) 更新

  • 要件:IDに基づいてユーザー情報を更新する
  • SQL:UPDATE user SET username = 'shunsuke', password = '123456', name = '松祐', age = 25 WHERE id = 1;
  • Mapperインターフェースメソッド:
/**
 * IDに基づいてユーザー情報を更新
 */
@Update("UPDATE user SET username = #{user.username}, password = #{user.password}, name = #{user.name}, age = #{user.age} WHERE id = #{user.id}")
void updateUser(@Param("user") User user);
  • ユニットテスト:
@Test
public void testUpdateUser() {
    User updatedUser = new User();
    updatedUser.setId(1);
    updatedUser.setUsername("adminUpdated");
    updatedUser.setPassword("123456");
    updatedUser.setName("管理者");
    updatedUser.setAge(31);
    userRepository.updateUser(updatedUser);
}

4-4) 取得

  • 要件:ユーザー名とパスワードに基づいてユーザー情報を取得する
  • SQL:SELECT * FROM user WHERE username = 'shunsuke' AND password = '123456'
  • Mapperインターフェースメソッド:
/**
 * ユーザー名とパスワードに基づいてユーザー情報を取得
 */
@Select("SELECT * FROM user WHERE username = #{username} AND password = #{password}")
User findUserByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
  • ユニットテスト:
@Test
public void testFindUserByUsernameAndPassword() {
    User foundUser = userRepository.findUserByUsernameAndPassword("adminUpdated", "123456");
    System.out.println(foundUser);
}

5. XMLマッピング構成

MyBatisの開発は主に2つの方法があります:

  • アノテーション
  • XML

5-1) XMLマッピングファイルの規範

単純なCRUD機能を実現するには、MyBatisのアノテーションを使用するのが一般的ですが、複雑なSQL機能を実現するには、XMLファイルでマッピングを設定することをお勧めします。

  • XMLマッピングファイルの名称は、Mapperインターフェースの名称と一致し、同じパッケージに配置します。
  • XMLマッピングファイルのnamespace属性は、Mapperインターフェースの完全修飾名と一致します。
  • XMLマッピングファイル内のSQL文のidは、Mapperインターフェースのメソッド名と一致し、戻り値の型も一致します。