Open3

MyBatisのソースコードを読んだ時のメモ

くそぼうずくそぼうず

ソースコードを読みたくなった背景

  • MyBatis経由でSELECT文を実行した時に、マッピングするクラスにprivateでいいからセッターを生やしておく必要があると教わったので、ソースコード的に真なのか調べたくなった。
  • InteliJの外部ライブラリでコードジャンプして読んでいく方向でソースコードを読んでいたが、いろんなクラスがあったりインタフェースの実装クラスがあり、どこに実装があるかぱっと見追えず、外部ライブラリでコードジャンプして読んでいくことに限界を感じた。なので、ライブラリ側でログをだして挙動を把握したいと思った。
くそぼうずくそぼうず

MyBatisのソースコードを読んだ時の手順(準備編)

  1. ソースコードをcloneする
  2. git checkout tags/mybatis-3.5.1して3.5.1のタグに切り替える
  3. InteliJで開く
  4. 準備をする(データベース側)
  • MySQLのサンプルデータベースのsakilaをローカル環境で使えるようにする ※今回はsakilaActorテーブルを使う
  1. 準備をする(MyBatis側)

    1. src/test/resources配下にsampleフォルダを作成し、設定ファイルを追加する
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "https://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
      <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
      </settings>
      <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://127.0.0.1:3306/sakila"/>
            <property name="username" value="設定したユーザ名"/>
            <property name="password" value="設定したパスワード"/>
          </dataSource>
        </environment>
      </environments>
      <mappers>
        <mapper resource="sample/ActorMapper.xml"/>
      </mappers>
    </configuration>
    
    1. src/test/resources配下にsampleフォルダの配下に、マッパーのXMLを追加する
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="org.apache.ibatis.sample.mapper.ActorMapper">
      <select id="selectActor" resultType="org.apache.ibatis.sample.entity.Actor">
        SELECT
          actor_id,
          last_name,
          first_name
        FROM actor
        WHERE actor_id = #{id}
      </select>
    </mapper>
    
    1. src/test/javasampleパッケージ配下にマッピングするクラスとマッパーのインタフェースを追加する
    Actor.java
    package org.apache.ibatis.sample.entity;
    
    public class Actor {
      private int actorId;
      private String firstName;
      private String lastName;
    
      public Actor(int actorId, String firstName, String lastName) {
        System.out.println("引数ありのコンストラクタが呼ばれた " + actorId + ", " + firstName + ", " + lastName);
        this.actorId = actorId;
        this.firstName = firstName;
        this.lastName = lastName;
      }
    
      public Actor() {
        System.out.println("引数なしのコンストラクタが呼ばれた");
      }
    
      public int getActorId() {
        return actorId;
      }
    
      public void setActorId(int actorId) {
        System.out.println("setActorIdが呼ばれた " + actorId);
        this.actorId = actorId;
      }
    
      public String getFirstName() {
        return firstName;
      }
    
      public void setFirstName(String firstName) {
        System.out.println("setFirstNameが呼ばれた " + firstName);
        this.firstName = firstName;
      }
    
      public String getLastName() {
        return lastName;
      }
    
      public void setLastName(String lastName) {
        System.out.println("setLastNameが呼ばれた " + lastName);
        this.lastName = lastName;
      }
    
      @Override
      public String toString() {
        return firstName + " " + lastName + " (id: " + actorId + ")";
      }
    }
    
    ActorMapper.java
    package org.apache.ibatis.sample.mapper;
    
    import org.apache.ibatis.sample.entity.Actor;
    
    public interface ActorMapper {
      Actor selectActor(int id);
    }
    
    
    1. src/test/java配下にsampleパッケージを作り、テストを追加する
    package org.apache.ibatis.sample;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.sample.entity.Actor;
    import org.apache.ibatis.sample.mapper.ActorMapper;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.jupiter.api.Test;
    
    import java.io.IOException;
    import java.io.InputStream;
    
    public class SampleTest {
      @Test
      void クエリを実行する() throws IOException {
        // https://mybatis.org/mybatis-3/ja/getting-started.html
    
        String resource = "sample/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
        try (SqlSession session = sqlSessionFactory.openSession()) {
          Actor actor = session.selectOne("org.apache.ibatis.sample.mapper.ActorMapper.selectActor", 101);
          System.out.println("実行結果: " + actor.toString());
        }
      }
    }
    
くそぼうずくそぼうず

MyBatisのソースコードを読んだ時の手順(実行編)

  1. 自身で追加したテストコードを実行して、DBに接続できて取得したレコードの内容が出力されるかどうか確認する
  2. (期待通り動くことが確認できたら)コードジャンプ機能を使って、気になる部分にSystem.out.println()を仕込んで、どのインタフェースを実装しているクラスやその時点の変数の値を確認する。または、ブレイクポイントを張って、デバック実行する。