Mapper の注入

MyBatis-Spring がスレッドセーフな Mapper を生成してくれるので、SqlSessionDaoSupportSqlSessionTemplate を使って手動で DAO オブジェクトを生成するコードは不要となります。 生成された Mapper は他の Bean に注入することができます。

<bean id="fooService" class="org.mybatis.spring.sample.service.FooServiceImpl">
  <constructor-arg ref="userMapper" />
</bean>

アプリケーション側の処理では、注入された Mapper のメソッドを呼び出すだけです。

public class FooServiceImpl implements FooService {

  private final UserMapper userMapper;

  public FooServiceImpl(UserMapper userMapper) {
    this.userMapper = userMapper;
  }

  public User doSomeBusinessStuff(String userId) {
    return this.userMapper.getUser(userId);
  }
}

このコードには SqlSession や MyBatis への参照が含まれていない点に注目してください。 また、セッションの生成やオープン、クローズも MyBatis-Spring が処理してくれるため不要となります。

Mapper の登録

Mapper を Bean として登録する方法は、Spring の設定を XML ファイルを使って行う場合と Spring 3.0 以降で導入された Java Config (= @Configuration) を使う場合で異なります。

XML で設定する場合

XML ファイルを使って Spring を設定する場合、次のように MapperFactoryBean のエントリーを追加することで Mapper を Spring Bean として登録することができます。

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

ここで指定した UserMapper のインターフェイスと同じクラスパスに MyBatis の XML Mapper ファイルが配置されている場合は自動的にロードされます。 XML Mapper が異なるクラスパスに配置されている場合を除けば、MyBatis の設定ファイルでこの Mapper を指定する必要はありません。 詳しくは SqlSessionFactoryBeanconfigLocation プロパティの説明を参照してください。

MapperFactoryBean を登録する際は SqlSessionFactory あるいは SqlSessionTemplate のどちらかを指定する必要があります。 指定対象のプロパティは、それぞれ sqlSessionFactorysqlSessionTemplate です。 両方が指定された場合、 SqlSessionFactory の指定は無視され、SqlSessionTemplate の登録時に指定した Session Factory が使われます。

Java Config で設定する場合

@Bean
public MapperFactoryBean<UserMapper> userMapper() throws Exception {
  MapperFactoryBean<UserMapper> factoryBean = new MapperFactoryBean<>(UserMapper.class);
  factoryBean.setSqlSessionFactory(sqlSessionFactory());
  return factoryBean;
}

Mapper の自動検出

上で説明した方法では Mapper を個別に指定していましたが、MyBatis-Spring では特定のクラスパスに含まれる Mapper を自動検出させることもできます。

これには3通りの方法があります。

  • <mybatis:scan/> 要素を使う。
  • @MapperScan アノテーションを使う。
  • Spring の XML 設定ファイルに MapperScannerConfigurer のエントリーを追加する。

<mybatis:scan/> または @MapperScan を使う場合は MyBatis-Spring 1.2.0 以降が必要です。また @MapperScan を使う場合は Spring 3.1 以降が必要となります。

2.0.2以降では、Mapperの自動検出機能は、Mapper Beanの遅延初期化の有効/無効を制御するオプション(lazy-initialization)をサポートします。 このオプションを追加する動機は、Spring Boot 2.2でサポートされた遅延初期化を制御する機能をサポートすることです。 このオプションのデフォルトはfalseです(遅延初期化を使用しません)。 開発者がMapper Beanを遅延初期化したい場合は、明示的にこのオプションをtrueに設定する必要があります。

重要 遅延初期化機能を使用する場合は、開発者は以下の制限を理解しておく必要があります。 以下の条件のいずれかに一致する場合、通常あなたのアプリケーションで遅延初期化機能を使用することはできません。

  • <association>(@One) and <collection>(@Many)を利用して、他のMapperのステートメントを参照している場合
  • <include>を利用して、他のMapperのフラグメントをインクルードしている場合
  • <cache-ref>(@CacheNamespaceRef)を利用して、他のMapperのキャッシュを参照している場合
  • <select resultMap="...">(@ResultMap)を利用して、他のMapperの結果マッピングを参照している場合

NOTE しかしながら、以下のように@DependsOn(Springの機能)を利用して、 依存するMapper Beanも同時に初期化すると遅延初期化機能を利用することができるようになります。

@DependsOn("vendorMapper")
public interface GoodsMapper {
  // ...
}

<mybatis:scan/>

<mybatis:scan/> は、Spring の <context:component-scan/> が Bean を検索するのと良く似た方法で Mapper を検出します。

XML 設定の例:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
  xsi:schemaLocation="
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
 
  <mybatis:scan base-package="org.mybatis.spring.sample.mapper" />

  <!-- ... -->

</beans>

base-package 属性で Mapper ファイルを含むパッケージを指定します。 セミコロンまたはカンマ区切りで複数のパッケージを指定することもできます。 また、指定されたパッケージが内包するパッケージも検索対象となります。

ここでは <mybatis:scan/>SqlSessionFactorySqlSessionTemplate を指定していませんが、この場合は Autowired 可能な MapperFactoryBean が自動的に生成されます。 ただし、複数の DataSource を利用する場合は Autowired に頼ることができないので、 factory-ref または template-ref 属性を使って適切な Bean を指定する必要があります。

<mybatis:scan/> を使う場合、マーカーインターフェイスまたはアノテーションを指定して Mapper をフィルタリングすることができます。 検出対象のアノテーションを指定するには annotation 属性を使います。 検出対象の Mapper が実装するインターフェイスを指定する場合は marker-interface 属性を使います。 両方の属性が指定された場合、どちらかの条件を満たすインターフェイスが Mapper として登録されます。 デフォルトではどちらも null となっており、base-package で指定したパッケージに含まれるすべてのインターフェイスが Mapper としてロードされます。

検出された Mapper は、Spring の自動検出コンポーネントに対するデフォルト命名規則によって Bean 名が決められます(the Spring reference document(Core Technologies -Naming autodetected components-) を参照してください)。 アノテーションによる指定がない場合はクラス名の先頭を小文字にした文字列が Bean 名となりますが、@Component あるいは JSR-330 の @Named アノテーションを使って Bean 名を明示的に指定することもできます。 先に説明した annotation 属性で org.springframework.stereotype.Componentjavax.inject.Named (Java 6 以降を利用している場合のみ)を指定すれば、検出時のマーカーと Bean 名の指定を1つのアノテーションで兼ねることができます。 同じ目的で独自に定義したアノテーションを使うこともできますが、このアノテーション自体に @Component か @Named を付加しておく必要があります。

NOTE Spring 標準の <context:component-scan/> を使って Mapper を検出することはできません。 Mapper はインターフェイスなので、各 Mapper に対する MapperFactoryBean の生成方法が分かっていないと Spring Bean として登録することができないのです。

@MapperScan

Java Config を使って Spring を設定しているのなら、<mybatis:scan/> よりも @MapperScan を使う方が気に入ると思います。

@MapperScan アノテーションは次のように使用します。

@Configuration
@MapperScan("org.mybatis.spring.sample.mapper")
public class AppConfig {
  // ...
}

このアノテーションは前章で説明した <mybatis:scan/> と全く同じ要領で Mapper の検出を行います。 引数 markerInterface, annotationClass を使えば検出対象のマーカーインターフェイスとアノテーションを指定することもできますし、sqlSessionFactory, sqlSessionTemplateSqlSessionFactorySqlSessionTemplate を指定することができます。

MapperScannerConfigurer

MapperScannerConfigurerBeanDefinitionRegistryPostProcessor として定義されているので、従来の XML による設定で通常の Bean として登録することができます。 MapperScannerConfigurer の登録は次のように行います。

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

特定の sqlSessionFactory または sqlSessionTemplate を指定する場合は、 Bean を参照ではなく 名前で 指定する必要があるので、ref ではなく value を使います。

<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

NOTE MyBatis-Spring 1.0.2 までは有効なプロパティは sqlSessionFactoryBeansqlSessionTemplateBean のみでしたが、 MapperScannerConfigurerPropertyPlaceholderConfigurer よりも先に読み込まれるためエラーの原因となっていました。 この問題を回避するため、これらのプロパティの使用は非推奨となり、新たに追加された sqlSessionFactoryBeanNamesqlSessionTemplateBeanName を使うことが推奨されています。