Java MyBatis フレームワーク

Java よく使うクラスライブラリ


MyBatis は優れた永続層フレームワークであり、Java アプリケーションとリレーショナルデータベース間のやり取りを簡素化します。MyBatis は XML またはアノテーション方式で SQL 文を Java オブジェクトにマッピングし、従来の JDBC プログラミングにおける大量のボイラープレートコードを回避します。


MyBatis のコア機能

1. SQL とコードの分離

MyBatis は開発者が SQL 文を Java コードから分離し、XML ファイルやアノテーションに格納することを可能にし、コードをより明確で保守しやすくします。

2. 自動マッピング

MyBatis はデータベースのクエリ結果を Java オブジェクトに自動的にマッピングできるため、データ変換の作業量を大幅に削減します。

3. 動的 SQL

MyBatis は強力な動的 SQL 機能を提供し、異なる条件に応じて異なる SQL 文を生成できます。

4. キャッシュメカニズム

MyBatis は一次キャッシュと二次キャッシュを内蔵しており、アプリケーションのパフォーマンスを効果的に向上させることができます。

MyBatis の基本アーキテクチャ

1. コアコンポーネント

  • SqlSessionFactory:SqlSession を作成するファクトリクラス
  • SqlSession:SQL コマンドを実行する主要インターフェース
  • Mapper インターフェース:データベース操作のメソッドを定義する
  • Mapper XML:SQL 文を含む設定ファイル

2. ワークフロー

  1. アプリケーションは SqlSessionFactoryBuilder を使用して SqlSessionFactory を作成します
  2. SqlSessionFactory が SqlSession を作成します
  3. SqlSession が Mapper インターフェースのインスタンスを取得します
  4. Mapper メソッドを呼び出してデータベース操作を実行します
  5. トランザクションをコミットし、SqlSession を閉じます

MyBatis の設定

1. メイン設定ファイル (mybatis-config.xml)

例

<?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>
    <environments default="development">
        <environment>
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis_db"/>
                <property name="username" value="root"/>
                <property name="password" value="password"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/example/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

2. Mapper ファイルの例

例

<?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.mapper.UserMapper">
    <select id="getUserById" parameterType="int" resultType="com.example.model.User">
        SELECT * FROM users WHERE id = #{id}
    </select>
   
    <insert id="insertUser" parameterType="com.example.model.User">
        INSERT INTO users(name, email) VALUES(#{name}, #{email})
    </insert>
</mapper>

MyBatis の基本的な使い方

1. SqlSession の取得

例

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();

2. クエリの実行

例

// 方法1:SqlSession を直接使用
User user = session.selectOne("com.example.mapper.UserMapper.getUserById", 1);

// 方法2:Mapper インターフェース経由
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.getUserById(1);

3. 挿入の実行

例

User newUser = new User();
newUser.setName("张三");
newUser.setEmail("[email protected]");

int rows = mapper.insertUser(newUser);
session.commit(); // トランザクションをコミット

MyBatis の動的 SQL

MyBatis は複数の動的 SQL 要素を提供し、異なる条件に応じて SQL 文を動的に生成できます:

1. if 要素

例

<select parameterType="map" resultType="User">
    SELECT * FROM users
    WHERE 1=1
    <if test="name != null">
        AND name = #{name}
    </if>
    <if test="email != null">
        AND email = #{email}
    </if>
</select>

2. choose/when/otherwise 要素

例

<select parameterType="map" resultType="User">
    SELECT * FROM users
    WHERE status = 'ACTIVE'
    <choose>
        <when test="name != null">
            AND name like #{name}
        </when>
        <when test="email != null">
            AND email = #{email}
        </when>
        <otherwise>
            AND 1=1
        </otherwise>
    </choose>
</select>

3. foreach 要素

例

<select parameterType="list" resultType="User">
    SELECT * FROM users
    WHERE id IN
    <foreach item="id" collection="list" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

MyBatis の関連クエリ

一対一関連

例

<resultMap type="User">
    <id property="id" column="user_id"/>
    <result property="name" column="user_name"/>
    <association property="address" javaType="Address">
        <id property="id" column="address_id"/>
        <result property="street" column="street"/>
        <result property="city" column="city"/>
    </association>
</resultMap>

<select resultMap="userWithAddress">
    SELECT
        u.id as user_id, u.name as user_name,
        a.id as address_id, a.street, a.city
    FROM users u
    LEFT JOIN addresses a ON u.address_id = a.id
    WHERE u.id = #{id}
</select>

一対多関連

例

<resultMap type="User">
    <id property="id" column="user_id"/>
    <result property="name" column="user_name"/>
    <collection property="orders" ofType="Order">
        <id property="id" column="order_id"/>
        <result property="orderDate" column="order_date"/>
        <result property="amount" column="amount"/>
    </collection>
</resultMap>

<select resultMap="userWithOrders">
    SELECT
        u.id as user_id, u.name as user_name,
        o.id as order_id, o.order_date, o.amount
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.id = #{id}
</select>

MyBatis のキャッシュメカニズム

1. 一次キャッシュ

一次キャッシュは SqlSession レベルのキャッシュで、デフォルトで有効です。同じ SqlSession 内では、同じクエリは SQL を一度だけ実行します。

特性:

  • 適用範囲:SqlSessionレベル(デフォルト有効、無効化不可)

  • ライフサイクル:SqlSessionの作成とともに作成され、SqlSessionのクローズとともに破棄されます

  • クリアが発生する条件:

    • 実行INSERT/UPDATE/DELETE操作

    • 呼び出しsqlSession.clearCache()

    • トランザクションのロールバックを実行

    • 異なる を設定Statement ID(SQL が同じでも)

注意事項:

例

// 例:同じ SqlSession 内で同じクエリは一度だけ実行される
User user1 = sqlSession.selectOne("getUserById", 1);  // SQL を実行
User user2 = sqlSession.selectOne("getUserById", 1);  // キャッシュから取得

2. 二次キャッシュ

二次キャッシュは Mapper レベルのキャッシュで、複数の SqlSession がキャッシュを共有できます。設定ファイルで有効にする必要があります:

<settings>
    <setting name="cacheEnabled" value="true"/>  <!-- 默认true可省略 -->
</settings>

また、Mapper ファイルで設定します:

<cache
  eviction="LRU"                <!-- 淘汰策略(默认LRU) -->
  flushInterval="60000"         <!-- 刷新间隔(毫秒) -->
  size="512"                    <!-- 缓存对象数量 -->
  readOnly="true"/>             <!-- 只读模式(性能更优) -->

キャッシュ戦略の比較:

戦略説明適用シナリオ
LRU最も最近使用されていない(LRU)通常の使用
FIFO先入れ先出し(FIFO)固定順序アクセス
SOFTソフト参照メモリに敏感なシナリオ
WEAK弱参照メモリに極めて敏感

MyBatis と Spring の統合

1. 依存関係の設定(現代の Spring Boot 推奨)

例

<!-- pom.xml -->
<dependencies>
    <!-- Spring Boot Starter 統合方式(推奨) -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>

    <!-- または従来の Spring プロジェクト向け -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>3.0.3</version>
    </dependency>
   
    <!-- データベースドライバは実際に合わせて選択 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version>
    </dependency>
</dependencies>

2. 設定方法(3つの主流な方式)

方式1:Spring Boot 自動設定(最も簡単)

例

# application.yml
mybatis
:
  mapper-locations
: classpath*:mapper/**/*.xml
  type-aliases-package
: com.example.model
  configuration
:
    map-underscore-to-camel-case
: true  # 自動キャメルケース変換

方式2:Java Config 完全設定(きめ細かい制御)

例

@Configuration
public class MyBatisConfig {
   
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setTypeAliasesPackage("com.example.model");
       
        // カスタム設定(例)
        org.apache.ibatis.session.Configuration config = new Configuration();
        config.setMapUnderscoreToCamelCase(true);
        config.setDefaultFetchSize(100);
        factory.setConfiguration(config);
       
        // プラグイン設定(例)
        factory.setPlugins(
            new MyBatisInterceptor(),
            new PaginationInterceptor()
        );
       
        return factory.getObject();
    }

    @Bean
    public MapperScannerConfigurer mapperScanner() {
        MapperScannerConfigurer scanner = new MapperScannerConfigurer();
        scanner.setBasePackage("com.example.mapper");
        scanner.setAnnotationClass(Repository.class); // アノテーションスキャンの限定
        return scanner;
    }
}

方式3:XML 従来設定(旧プロジェクトとの互換性)

例

<!-- applicationContext.xml -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.mapper"/>
</bean>

3. トランザクション管理設定

例

@Configuration
@EnableTransactionManagement
public class TransactionConfig {
   
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
   
    // トランザクションテンプレートを定義可能
    @Bean
    public TransactionTemplate transactionTemplate(PlatformTransactionManager manager) {
        return new TransactionTemplate(manager);
    }
}

4. 使用規範とベストプラクティス

Mapper インターフェース定義:

例

@Repository // DAO 層のアノテーションを明確に指定
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User selectById(@Param("id") int id);
   
    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("INSERT INTO users(name) VALUES(#{name})")
    int insert(User user);
}

Service 層の例:

例

@Service
@Transactional(readOnly = true) // デフォルトは読み取り専用
public class UserService {
   
    private final UserMapper userMapper;
   
    @Autowired // コンストラクタインジェクション推奨
    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
   
    @Transactional // 書き込み操作はトランザクションを個別に開始
    public User createUser(String name) {
        User user = new User();
        user.setName(name);
        userMapper.insert(user);
        return userMapper.selectById(user.getId());
    }
}

5. 高度な機能統合

動的データソース設定:

例

@Bean
@Primary
public DataSource dynamicDataSource() {
    DynamicDataSource ds = new DynamicDataSource();
    ds.setDefaultTargetDataSource(primaryDataSource());
    ds.setTargetDataSources(Map.of(
        "master", primaryDataSource(),
        "slave", secondaryDataSource()
    ));
    return ds;
}

複数データソースのトランザクション管理:

例

@Bean
public PlatformTransactionManager transactionManager() {
    return new ChainedTransactionManager(
        new JpaTransactionManager(entityManagerFactory()),
        new DataSourceTransactionManager(dataSource())
    );
}

MyBatis のベストプラクティス

  1. SqlSession を直接使用するのではなく、Mapper インターフェースを使用する:これにより、コードはより型安全で、保守も容易になります。
  2. 動的 SQL を適切に使用する:SQL インジェクションのリスクを回避し、SQL の可読性を維持します。
  3. バッチ操作:大規模なデータ操作では、バッチ処理を使用してパフォーマンスを向上させます。
  4. キャッシュを適切に使用する:ビジネス要件に応じて適切なキャッシュ戦略を設定します。
  5. SQL最適化:Mapper XML で効率的な SQL 文を作成します。

MyBatis は柔軟で強力な ORM フレームワークであり、適切に使用することで開発効率とアプリケーションのパフォーマンスを大幅に向上させることができます。この記事が MyBatis フレームワークの理解と使用に役立つことを願っています。

Java 常用ライブラリ

その他の拡張