設定
MyBatis の設定には、MyBatis の動作に大きな影響を与える設定とプロパティが含まれています。ドキュメントの全体的な構造は次のとおりです。
- configuration
- properties
- settings
- typeAliases
- typeHandlers
- objectFactory
- plugins
- environments
- environment
- transactionManager
- dataSource
- environment
- databaseIdProvider
- mappers
properties
これらは、典型的な Java Properties ファイルインスタンスで設定するか、properties 要素のサブ要素を介して渡すことができる、外部化可能で置換可能なプロパティです。例:
<properties resource="org/mybatis/example/config.properties">
<property name="username" value="dev_user"/>
<property name="password" value="F2Fa3!33TYyg"/>
</properties>
プロパティは、動的に構成する必要がある値を置き換えるために、構成ファイル全体で使用できます。例:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
この例の username と password は、properties 要素で設定された値に置き換えられます。driver と url プロパティは、config.properties ファイルに含まれる値に置き換えられます。これにより、構成に多くのオプションが提供されます。
プロパティは、SqlSessionFactoryBuilder.build() メソッドに渡すこともできます。例:
SqlSessionFactory factory =
sqlSessionFactoryBuilder.build(reader, props);
// ... or ...
SqlSessionFactory factory =
new SqlSessionFactoryBuilder.build(reader, environment, props);
プロパティがこれらの複数の場所に存在する場合、MyBatis は次の順序でそれらを読み込みます。
- properties 要素の本文で指定されたプロパティが最初に読み込まれ、
- properties 要素の classpath リソースまたは url 属性からロードされたプロパティは 2 番目に読み込まれ、すでに指定されている重複するプロパティを上書きし、
- メソッドパラメータとして渡されたプロパティは最後に読み込まれ、properties の本文および resource/url 属性からロードされた可能性のある重複するプロパティを上書きします。
したがって、最も優先度の高いプロパティは、メソッドパラメータとして渡されたものであり、次に resource/url 属性、最後に properties 要素の本文で指定されたプロパティとなります。
MyBatis 3.4.2 以降では、次のようにプレースホルダーにデフォルト値を指定できます。
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${username:ut_user}"/> <!-- If 'username' property not present, username become 'ut_user' -->
</dataSource>
この機能はデフォルトでは無効になっています。プレースホルダーにデフォルト値を指定する場合は、次の特別なプロパティを追加してこの機能を有効にする必要があります。
<properties resource="org/mybatis/example/config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- Enable this feature -->
</properties>
注意 これは、プロパティキー (例: db:username) 内の ":" 文字、または SQL 定義の OGNL 式の三項演算子 (例: ${tableName != null ? tableName : 'global_constants'}) と競合します。どちらかを使用しており、デフォルトのプロパティ値が必要な場合は、この特別なプロパティを追加してデフォルト値の区切り文字を変更する必要があります。
<properties resource="org/mybatis/example/config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.default-value-separator" value="?:"/> <!-- Change default value of separator -->
</properties>
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${db:username?:ut_user}"/>
</dataSource>
settings
これらは、MyBatis が実行時に動作する方法を変更する非常に重要な微調整です。次の表に、設定、その意味、およびデフォルト値を示します。
| 設定 | 説明 | 有効な値 | デフォルト |
|---|---|---|---|
| cacheEnabled | この構成下の任意のマッパーで構成されたキャッシュをグローバルに有効または無効にします。 | true | false | true |
| lazyLoadingEnabled | 遅延ロードをグローバルに有効または無効にします。有効にすると、すべてのリレーションが遅延ロードされます。この値は、fetchType 属性を使用することで、特定のリレーションに対して上書きできます。 |
true | false | false |
| aggressiveLazyLoading | 有効にすると、メソッド呼び出しごとにオブジェクトのすべての遅延プロパティがロードされます。それ以外の場合、各プロパティはオンデマンドでロードされます (lazyLoadTriggerMethods も参照してください)。 |
true | false | false (≤3.4.1 では true) |
| multipleResultSetsEnabled | 単一のステートメントから複数の ResultSets を返すことを許可または禁止します (互換性のあるドライバが必要)。 | true | false | true |
| useColumnLabel | 列名ではなく、列ラベルを使用します。この点に関して、異なるドライバは異なる動作をします。ドライバのドキュメントを参照するか、両方のモードをテストして、ドライバがどのように動作するかを判断してください。 | true | false | true |
| useGeneratedKeys | 生成されたキーに対する JDBC サポートを許可します。互換性のあるドライバが必要です。この設定は、一部のドライバでは互換性を否定するものの、依然として機能するため (例: Derby)、true に設定されている場合は生成されたキーを強制的に使用します。 | true | false | False |
| autoMappingBehavior | MyBatis が列をフィールド/プロパティに自動的にマップする方法と、その場合のマッピング方法を指定します。NONE は自動マッピングを無効にします。PARTIAL は、内部にネストされた結果マッピングが定義されていない結果のみを自動マップします。FULL は、複雑さ (ネストされたものを含む) に関係なく結果マッピングを自動マップします。 | NONE、PARTIAL、FULL | PARTIAL |
| autoMappingUnknownColumnBehavior | 自動マッピングのターゲットの不明な列 (または不明なプロパティタイプ) が検出された場合の動作を指定します。
autoMappingBehavior が FULL に設定されている場合は、誤検知が発生する可能性があることに注意してください。 |
NONE、WARNING、FAILING | NONE |
| defaultExecutorType | デフォルトのエグゼキュータを構成します。SIMPLE エグゼキュータは特別な処理をしません。REUSE エグゼキュータはプリペアドステートメントを再利用します。BATCH エグゼキュータはステートメントを再利用し、更新をバッチ処理します。 | SIMPLE REUSE BATCH | SIMPLE |
| defaultStatementTimeout | ドライバがデータベースからの応答を待機する秒数を設定します。 | 任意の正の整数 | 設定されていません (null) |
| defaultFetchSize | 返される結果のフェッチサイズを制御するためのヒントとしてドライバを設定します。このパラメータ値は、クエリ設定によって上書きできます。 | 任意の正の整数 | 設定されていません (null) |
| defaultResultSetType | ステートメント設定ごとに省略した場合のスクロール戦略を指定します。(Since: 3.5.2) | FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(「未設定」と同じ動作) | 設定されていません (null) |
| safeRowBoundsEnabled | ネストされたステートメントで RowBounds を使用できるようにします。許可する場合は、false に設定します。 | true | false | False |
| safeResultHandlerEnabled | ネストされたステートメントで ResultHandler を使用できるようにします。許可する場合は、false に設定します。 | true | false | True |
| mapUnderscoreToCamelCase | クラシックなデータベースの列名 A_COLUMN からキャメルケースのクラシックな Java プロパティ名 aColumn への自動マッピングを有効にします。 | true | false | False |
| localCacheScope | MyBatis はローカルキャッシュを使用して、循環参照を防ぎ、繰り返されるネストされたクエリを高速化します。デフォルト (SESSION) では、セッション中に実行されるすべてのクエリがキャッシュされます。localCacheScope=STATEMENT の場合、ローカルセッションはステートメントの実行にのみ使用され、同じ SqlSession の 2 つの異なる呼び出し間でデータが共有されることはありません。 | SESSION | STATEMENT | SESSION |
| jdbcTypeForNull | パラメータに特定の JDBC タイプが指定されていない場合に、null 値に使用する JDBC タイプを指定します。一部のドライバでは、列の JDBC タイプを指定する必要がありますが、他のドライバでは、NULL、VARCHAR、OTHER などの汎用値で動作します。 | JdbcType 列挙。最も一般的なものは、NULL、VARCHAR、OTHER です。 | OTHER |
| lazyLoadTriggerMethods | 遅延ロードをトリガーするオブジェクトのメソッドを指定します | カンマで区切られたメソッド名リスト | equals,clone,hashCode,toString |
| defaultScriptingLanguage | 動的 SQL 生成に使用されるデフォルトの言語を指定します。 | 型エイリアスまたは完全修飾クラス名。 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
| defaultEnumTypeHandler | Enum のデフォルトで使用される TypeHandler を指定します。(Since: 3.4.5) |
型エイリアスまたは完全修飾クラス名。 | org.apache.ibatis.type.EnumTypeHandler |
| callSettersOnNulls | 取得した値が null の場合に、セッターまたはマップの put メソッドが呼び出されるかどうかを指定します。Map.keySet() または null 値の初期化に依存する場合に役立ちます。(int、boolean など) などのプリミティブは null に設定されないことに注意してください。 | true | false | false |
| returnInstanceForEmptyRow | デフォルトでは、MyBatis は、返された行のすべての列が NULL の場合に null を返します。この設定が有効になっている場合、MyBatis は代わりに空のインスタンスを返します。ネストされた結果 (つまり、コレクションと関連付け) にも適用されることに注意してください。Since: 3.4.2 |
true | false | false |
| logPrefix | MyBatis がロガー名に追加するプレフィックス文字列を指定します。 | 任意の文字列 | 設定されていません |
| logImpl | MyBatis が使用するロギング実装を指定します。この設定が存在しない場合、ロギング実装は自動検出されます。 | SLF4J | LOG4J(3.5.9 以降非推奨) | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 設定されていません |
| proxyFactory | MyBatis が遅延ロード対応オブジェクトの作成に使用するプロキシツールを指定します。 | CGLIB (3.5.10 以降非推奨) | JAVASSIST | JAVASSIST (MyBatis 3.3 以降) |
| vfsImpl | VFS 実装を指定します | カンマで区切られたカスタム VFS 実装の完全修飾クラス名。 | 設定されていません |
| useActualParamName | メソッドシグネチャで宣言された実際の名前でステートメントパラメータを参照できるようにします。この機能を使用するには、プロジェクトを Java 8 で -parameters オプションを使用してコンパイルする必要があります。(Since: 3.4.1) |
true | false | true |
| configurationFactory | Configuration のインスタンスを提供するクラスを指定します。返された Configuration インスタンスは、デシリアライズされたオブジェクトの遅延プロパティをロードするために使用されます。このクラスには、static Configuration getConfiguration() というシグネチャのメソッドが必要です。(Since: 3.2.3) |
型エイリアスまたは完全修飾クラス名。 | 設定されていません |
| shrinkWhitespacesInSql | SQL から余分な空白文字を削除します。これにより、SQL のリテラル文字列にも影響を与えることに注意してください。(Since 3.5.5) | true | false | false |
| defaultSqlProviderType | プロバイダメソッドを保持する SQL プロバイダクラスを指定します (Since 3.5.6)。このクラスは、SQL プロバイダのアノテーション (例: @SelectProvider) の type (または value) 属性に適用されます。これらの属性が省略された場合。 |
型エイリアスまたは完全修飾クラス名 | 設定されていません |
| nullableOnForEach | ‘foreach’ タグの ‘nullable’ 属性のデフォルト値を指定します。(Since 3.5.9) | true | false | false |
| argNameBasedConstructorAutoMapping | コンストラクタの自動マッピングを適用する場合、列の順序に依存するのではなく、引数名を使用してマッピングする列を検索します。(Since 3.5.10) | true | false | false |
完全に構成された設定要素の例を次に示します。
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<setting name="safeRowBoundsEnabled" value="false"/>
<setting name="safeResultHandlerEnabled" value="true"/>
<setting name="mapUnderscoreToCamelCase" value="false"/>
<setting name="localCacheScope" value="SESSION"/>
<setting name="jdbcTypeForNull" value="OTHER"/>
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
<setting name="defaultScriptingLanguage" value="org.apache.ibatis.scripting.xmltags.XMLLanguageDriver"/>
<setting name="defaultEnumTypeHandler" value="org.apache.ibatis.type.EnumTypeHandler"/>
<setting name="callSettersOnNulls" value="false"/>
<setting name="returnInstanceForEmptyRow" value="false"/>
<setting name="logPrefix" value="exampleLogPreFix_"/>
<setting name="logImpl" value="SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING"/>
<setting name="proxyFactory" value="CGLIB | JAVASSIST"/>
<setting name="vfsImpl" value="org.mybatis.example.YourselfVfsImpl"/>
<setting name="useActualParamName" value="true"/>
<setting name="configurationFactory" value="org.mybatis.example.ConfigurationFactory"/>
</settings>
typeAliases
型エイリアスは、Java 型の単なる短い名前です。XML 構成にのみ関連し、完全修飾クラス名の冗長な入力を減らすためだけに存在します。例:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
この設定により、Blog は domain.blog.Blog が使用されていた場所ならどこでも使用できるようになります。
MyBatis が Bean を検索するパッケージを指定することもできます。例:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
domain.blog 内で見つかった各 Bean は、アノテーションが見つからない場合、Bean の非修飾クラス名を小文字にしたものがエイリアスとして登録されます。つまり、domain.blog.Author は author として登録されます。@Alias アノテーションが見つかった場合は、その値がエイリアスとして使用されます。以下の例をご覧ください。
@Alias("author")
public class Author {
...
}
一般的な Java 型には、多くの組み込み型エイリアスがあります。これらはすべて大文字と小文字を区別しません。オーバーロードされた名前のため、プリミティブの特別な処理に注意してください。
| エイリアス | マップされた型 |
|---|---|
| _byte | byte |
| _char (3.5.10 以降) | char |
| _character (3.5.10 以降) | char |
| _long | long |
| _short | short |
| _int | int |
| _integer | int |
| _double | double |
| _float | float |
| _boolean | boolean |
| string | String |
| byte | Byte |
| char (3.5.10 以降) | Character |
| character (3.5.10 以降) | Character |
| long | Long |
| short | Short |
| int | Integer |
| integer | Integer |
| double | Double |
| float | Float |
| boolean | Boolean |
| date | Date |
| decimal | BigDecimal |
| bigdecimal | BigDecimal |
| biginteger | BigInteger |
| object | Object |
| date[] | Date[] |
| decimal[] | BigDecimal[] |
| bigdecimal[] | BigDecimal[] |
| biginteger[] | BigInteger[] |
| object[] | Object[] |
| map | Map |
| hashmap | HashMap |
| list | List |
| arraylist | ArrayList |
| collection | Collection |
| iterator | Iterator |
typeHandlers
MyBatis が PreparedStatement にパラメータを設定したり、ResultSet から値を取得したりするたびに、TypeHandler が使用されて、Java 型に適した方法で値が取得されます。次の表は、デフォルトの TypeHandler について説明しています。
注 バージョン 3.4.5 以降、MyBatis は JSR-310(日付と時刻の API)をデフォルトでサポートしています。
| タイプハンドラ | Java タイプ | JDBC タイプ |
|---|---|---|
BooleanTypeHandler |
java.lang.Boolean, boolean |
互換性のある任意の BOOLEAN |
ByteTypeHandler |
java.lang.Byte, byte |
互換性のある任意の NUMERIC または BYTE |
ShortTypeHandler |
java.lang.Short, short |
互換性のある任意の NUMERIC または SMALLINT |
IntegerTypeHandler |
java.lang.Integer, int |
互換性のある任意の NUMERIC または INTEGER |
LongTypeHandler |
java.lang.Long, long |
互換性のある任意の NUMERIC または BIGINT |
FloatTypeHandler |
java.lang.Float, float |
互換性のある任意の NUMERIC または FLOAT |
DoubleTypeHandler |
java.lang.Double, double |
互換性のある任意の NUMERIC または DOUBLE |
BigDecimalTypeHandler |
java.math.BigDecimal |
互換性のある任意の NUMERIC または DECIMAL |
StringTypeHandler |
java.lang.String |
CHAR, VARCHAR |
ClobReaderTypeHandler |
java.io.Reader |
- |
ClobTypeHandler |
java.lang.String |
CLOB, LONGVARCHAR |
NStringTypeHandler |
java.lang.String |
NVARCHAR, NCHAR |
NClobTypeHandler |
java.lang.String |
NCLOB |
BlobInputStreamTypeHandler |
java.io.InputStream |
- |
ByteArrayTypeHandler |
byte[] |
互換性のある任意のバイトストリーム型 |
BlobTypeHandler |
byte[] |
BLOB, LONGVARBINARY |
DateTypeHandler |
java.util.Date |
TIMESTAMP |
DateOnlyTypeHandler |
java.util.Date |
DATE |
TimeOnlyTypeHandler |
java.util.Date |
TIME |
SqlTimestampTypeHandler |
java.sql.Timestamp |
TIMESTAMP |
SqlDateTypeHandler |
java.sql.Date |
DATE |
SqlTimeTypeHandler |
java.sql.Time |
TIME |
ObjectTypeHandler |
Any | OTHER, または未指定 |
EnumTypeHandler |
列挙型 | VARCHAR コードが保存されるため、任意の文字列互換型(インデックスではありません)。 |
EnumOrdinalTypeHandler |
列挙型 | 位置が保存されるため、互換性のある任意の NUMERIC または DOUBLE(コード自体ではありません)。 |
SqlxmlTypeHandler |
java.lang.String |
SQLXML |
InstantTypeHandler |
java.time.Instant |
TIMESTAMP |
LocalDateTimeTypeHandler |
java.time.LocalDateTime |
TIMESTAMP |
LocalDateTypeHandler |
java.time.LocalDate |
DATE |
LocalTimeTypeHandler |
java.time.LocalTime |
TIME |
OffsetDateTimeTypeHandler |
java.time.OffsetDateTime |
TIMESTAMP |
OffsetTimeTypeHandler |
java.time.OffsetTime |
TIME |
ZonedDateTimeTypeHandler |
java.time.ZonedDateTime |
TIMESTAMP |
YearTypeHandler |
java.time.Year |
INTEGER |
MonthTypeHandler |
java.time.Month |
INTEGER |
YearMonthTypeHandler |
java.time.YearMonth |
VARCHAR または LONGVARCHAR |
JapaneseDateTypeHandler |
java.time.chrono.JapaneseDate |
DATE |
タイプハンドラをオーバーライドしたり、サポートされていない型または非標準の型を処理するために独自のタイプハンドラを作成したりできます。そのためには、インターフェース org.apache.ibatis.type.TypeHandler を実装するか、便利なクラス org.apache.ibatis.type.BaseTypeHandler を拡張し、必要に応じて JDBC 型にマッピングします。例:
// ExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class ExampleTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
String parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName)
throws SQLException {
return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex)
throws SQLException {
return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex)
throws SQLException {
return cs.getString(columnIndex);
}
}
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.mybatis.example.ExampleTypeHandler"/>
</typeHandlers>
このような TypeHandler を使用すると、Java String プロパティと VARCHAR パラメータおよび結果に対する既存のタイプハンドラがオーバーライドされます。MyBatis はデータベースのメタデータを調べて型を判断しないため、正しいタイプハンドラをフックするには、パラメータと結果のマッピングで VARCHAR フィールドであることを指定する必要があります。これは、MyBatis がステートメントが実行されるまでデータ型を認識しないという事実によるものです。
MyBatis は、ジェネリック型をイントロスペクトすることにより、この TypeHandler で処理したい Java 型を認識しますが、この動作を 2 つの方法でオーバーライドできます。
- typeHandler 要素に
javaType属性を追加する (例:javaType="String") - TypeHandler クラスに
@MappedTypesアノテーションを追加して、関連付ける Java 型のリストを指定する。このアノテーションは、javaType属性も指定されている場合は無視されます。
関連付けられた JDBC 型は、次の 2 つの方法で指定できます。
- typeHandler 要素に
jdbcType属性を追加する (例:jdbcType="VARCHAR")。 - TypeHandler クラスに
@MappedJdbcTypesアノテーションを追加して、関連付ける JDBC 型のリストを指定する。このアノテーションは、jdbcType属性も指定されている場合は無視されます。
ResultMap で使用する TypeHandler を決定する場合、Java 型は (結果型から) わかっていますが、JDBC 型は不明です。したがって、MyBatis は javaType=[TheJavaType], jdbcType=null の組み合わせを使用して TypeHandler を選択します。これは、@MappedJdbcTypes アノテーションを使用すると、TypeHandler のスコープが 制限され、明示的に設定しない限り、ResultMap での使用が不可能になることを意味します。TypeHandler を ResultMap で使用できるようにするには、@MappedJdbcTypes アノテーションで includeNullJdbcType=true を設定します。ただし、Mybatis 3.4.0 以降では、Java 型を処理するために 単一 の TypeHandler が登録されている場合、この Java 型を使用する ResultMap では (includeNullJdbcType=true がなくても) デフォルトで使用されます。
最後に、MyBatis に TypeHandler を検索させることができます。
<!-- mybatis-config.xml -->
<typeHandlers>
<package name="org.mybatis.example"/>
</typeHandlers>
自動検出機能を使用する場合、JDBC 型はアノテーションでのみ指定できることに注意してください。
複数のクラスを処理できる汎用的な TypeHandler を作成できます。そのためには、クラスをパラメータとして受け取るコンストラクタを追加すると、MyBatis は TypeHandler を構築するときに実際のクラスを渡します。
//GenericTypeHandler.java
public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> {
private Class<E> type;
public GenericTypeHandler(Class<E> type) {
if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
this.type = type;
}
...
EnumTypeHandler と EnumOrdinalTypeHandler は汎用 TypeHandler です。これらについては、次のセクションで学びます。
列挙型の処理
Enum をマッピングする場合は、EnumTypeHandler または EnumOrdinalTypeHandler のいずれかを使用する必要があります。
たとえば、数値を丸める必要がある場合に、使用する必要がある丸めモードを格納する必要があるとします。デフォルトでは、MyBatis は EnumTypeHandler を使用して、Enum 値をその名前に変換します。
EnumTypeHandler は、他のハンドラとは異なり、特定のクラスだけを処理するのではなく、Enum を拡張する任意のクラスを処理するという意味で特別なものです。
ただし、名前を保存したくない場合があります。DBA は代わりに整数コードを主張するかもしれません。それは簡単です。設定ファイルの typeHandlers に EnumOrdinalTypeHandler を追加すると、各 RoundingMode はその序数値を使用して整数にマッピングされるようになります。
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler"
javaType="java.math.RoundingMode"/>
</typeHandlers>
しかし、同じ Enum をある場所では文字列に、別の場所では整数にマッピングしたい場合はどうすればよいでしょうか。
オートマッパーは自動的に EnumOrdinalTypeHandler を使用するため、通常の EnumTypeHandler を使用する場合に戻すには、これらの SQL ステートメントに使用するタイプハンドラを明示的に設定して指示する必要があります。
(マッパーファイルは次のセクションまで説明されていないため、ドキュメントを初めて読む場合は、今はスキップして後で戻ってくることをお勧めします。)
<!DOCTYPE mapper
PUBLIC "-//mybatis.dokyumento.jp//DTD Mapper 3.0//EN"
"https://mybatis.dokyumento.jp/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode"/>
</resultMap>
<select id="getUser" resultMap="usermap">
select * from users
</select>
<insert id="insert">
insert into users (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode}
)
</insert>
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode"
typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
</resultMap>
<select id="getUser2" resultMap="usermap2">
select * from users2
</select>
<insert id="insert2">
insert into users2 (id, name, funkyNumber, roundingMode) values (
#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
)
</insert>
</mapper>
これにより、select ステートメントで resultType ではなく resultMap を使用する必要があることに注意してください。
objectFactory
MyBatis が結果オブジェクトの新しいインスタンスを作成するたびに、ObjectFactory インスタンスを使用してそれを行います。デフォルトの ObjectFactory は、デフォルトコンストラクタ、またはパラメータマッピングが存在する場合はパラメータ化されたコンストラクタを使用してターゲットクラスをインスタンス化する以上のことはほとんど行いません。ObjectFactory のデフォルトの動作をオーバーライドする場合は、独自の ObjectFactory を作成できます。例:
// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
@Override
public <T> T create(Class<T> type) {
return super.create(type);
}
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
return super.create(type, constructorArgTypes, constructorArgs);
}
@Override
public void setProperties(Properties properties) {
super.setProperties(properties);
}
@Override
public <T> boolean isCollection(Class<T> type) {
return Collection.class.isAssignableFrom(type);
}
}
<!-- mybatis-config.xml -->
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
<property name="someProperty" value="100"/>
</objectFactory>
ObjectFactory インターフェースは非常にシンプルです。デフォルトコンストラクタを処理するためのメソッドと、パラメータ化されたコンストラクタを処理するためのメソッドの 2 つの作成メソッドが含まれています。最後に、setProperties メソッドを使用して ObjectFactory を構成できます。objectFactory 要素の本体内で定義されたプロパティは、ObjectFactory インスタンスの初期化後に setProperties メソッドに渡されます。
plugins
MyBatis では、マップされたステートメントの実行中の特定のポイントで呼び出しをインターセプトできます。デフォルトでは、MyBatis ではプラグインが次のメソッド呼び出しをインターセプトできます。
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
これらのクラスメソッドの詳細は、各メソッドの完全な署名と、各MyBatisリリースで利用可能なソースコードを参照することで確認できます。呼び出しを監視する以上のことを行う場合は、オーバーライドするメソッドの動作を理解する必要があります。特定のメソッドの動作を変更またはオーバーライドしようとすると、MyBatisのコアを壊す可能性があります。これらは低レベルのクラスとメソッドであるため、プラグインの使用には注意が必要です。
プラグインは、提供される強力な機能からすると、非常に簡単に使用できます。インターセプトしたい署名を指定して、Interceptorインターフェースを実装するだけです。
// ExamplePlugin.java
@Intercepts({@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {
private Properties properties = new Properties();
@Override
public Object intercept(Invocation invocation) throws Throwable {
// implement pre-processing if needed
Object returnObject = invocation.proceed();
// implement post-processing if needed
return returnObject;
}
@Override
public void setProperties(Properties properties) {
this.properties = properties;
}
}
<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
上記のプラグインは、マッピングされたステートメントの低レベルの実行を担当する内部オブジェクトであるExecutorインスタンスの「update」メソッドへのすべての呼び出しをインターセプトします。
注 Configurationクラスのオーバーライド
プラグインを使用してMyBatisのコアの動作を変更するだけでなく、Configurationクラス全体をオーバーライドすることもできます。単純にそれを拡張し、内部の任意のメソッドをオーバーライドして、SqlSessionFactoryBuilder.build(myConfig)メソッドの呼び出しに渡します。ただし、これもMyBatisの動作に深刻な影響を与える可能性があるため、注意して使用してください。
environments
MyBatisは複数の環境で構成できます。これにより、さまざまな理由でSQLマップを複数のデータベースに適用できます。たとえば、開発、テスト、および本番環境で異なる構成を使用できます。または、同じスキーマを共有する複数の本番データベースがあり、両方に同じSQLマップを使用したい場合があります。多くのユースケースがあります。
ただし、覚えておくべき重要なことの1つは、複数の環境を構成できますが、SqlSessionFactoryインスタンスごとに1つしか選択できないということです。
したがって、2つのデータベースに接続する場合は、それぞれに1つずつ、2つのSqlSessionFactoryインスタンスを作成する必要があります。3つのデータベースの場合は、3つのインスタンスが必要になります。覚えやすいですね。
- データベースごとに1つのSqlSessionFactoryインスタンス
どの環境を構築するかを指定するには、SqlSessionFactoryBuilderにオプションのパラメーターとして渡します。環境を受け入れる2つの署名は次のとおりです。
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
環境が省略されている場合は、以下に示すように、デフォルトの環境がロードされます。
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
environments要素は、環境の構成方法を定義します。
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
ここで重要なセクションに注目してください。
- デフォルトのEnvironment ID(例:default="development")。
- 定義された各環境のEnvironment ID(例:id="development")。
- TransactionManagerの構成(例:type="JDBC")
- DataSourceの構成(例:type="POOLED")
デフォルトの環境と環境IDは自明です。好きなように名前を付けてください。デフォルトがそれらのいずれかと一致するようにしてください。
transactionManager
MyBatisに含まれているTransactionManagerタイプは2つあります(つまり、type="[JDBC|MANAGED]")。
-
JDBC – この構成は、JDBCのコミットおよびロールバック機能を直接利用します。トランザクションのスコープを管理するためにdataSourceから取得した接続に依存します。デフォルトでは、一部のドライバーとの互換性のために、接続を閉じるときに自動コミットを有効にします。ただし、一部のドライバーでは、自動コミットを有効にすることは不必要なだけでなく、コストのかかる操作でもあります。したがって、バージョン3.5.10以降では、「skipSetAutoCommitOnClose」プロパティをtrueに設定することで、この手順をスキップできます。例:
<transactionManager type="JDBC"> <property name="skipSetAutoCommitOnClose" value="true"/> </transactionManager> -
MANAGED – この構成は、ほとんど何もしません。接続をコミットまたはロールバックすることはありません。代わりに、コンテナがトランザクションの完全なライフサイクルを管理できるようにします(例:JEEアプリケーションサーバーコンテキスト)。デフォルトでは、接続を閉じます。ただし、一部のコンテナではこれを予期していないため、接続を閉じないようにする必要がある場合は、「closeConnection」プロパティをfalseに設定します。例:
<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>
注 SpringでMyBatisを使用する予定の場合は、Springモジュールが独自のトランザクションマネージャーを設定し、以前に設定された構成をオーバーライドするため、TransactionManagerを構成する必要はありません。
これらのTransactionManagerタイプには、プロパティは必要ありません。ただし、どちらもタイプエイリアスであるため、代わりに、独自のTransactionFactoryインターフェースの実装を参照する、完全修飾クラス名またはタイプエイリアスを使用することもできます。
public interface TransactionFactory {
default void setProperties(Properties props) { // Since 3.5.2, change to default method
// NOP
}
Transaction newTransaction(Connection conn);
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
XMLで構成されたプロパティは、インスタンス化後にsetProperties()メソッドに渡されます。実装では、Transaction実装も作成する必要があります。これも非常に単純なインターフェースです。
public interface Transaction {
Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;
}
これらの2つのインターフェースを使用すると、MyBatisがトランザクションを処理する方法を完全にカスタマイズできます。
dataSource
dataSource要素は、標準のJDBC DataSourceインターフェースを使用してJDBC接続オブジェクトのソースを構成します。
ほとんどのMyBatisアプリケーションは、例のようにdataSourceを構成します。ただし、必須ではありません。ただし、遅延ロードを容易にするには、このdataSourceが必要であることに注意してください。
組み込みのdataSourceタイプは3つあります(つまり、type="[UNPOOLED|POOLED|JNDI]")。
UNPOOLED – このDataSourceの実装は、リクエストされるたびに接続を開閉するだけです。少し遅いですが、すぐに利用可能な接続のパフォーマンスを必要としない単純なアプリケーションに適しています。このパフォーマンスの領域もデータベースによって異なるため、一部のデータベースではプールすることがそれほど重要ではない可能性があり、この構成が理想的です。UNPOOLED DataSourceには、次の構成プロパティがあります。
driver– これはJDBCドライバーの完全修飾Javaクラスです(ドライバーにDataSourceクラスが含まれている場合は、DataSourceクラスではありません)。url– これは、データベースインスタンスのJDBC URLです。username– ログインに使用するデータベースのユーザー名。password– ログインに使用するデータベースのパスワード。defaultTransactionIsolationLevel– 接続のデフォルトのトランザクション分離レベル。defaultNetworkTimeout– データベース操作が完了するのを待機するデフォルトのネットワークタイムアウト値(ミリ秒単位)。詳細については、java.sql.Connection#setNetworkTimeout()のAPIドキュメントを参照してください。
オプションで、データベースドライバーにプロパティを渡すこともできます。これを行うには、プロパティにdriver.というプレフィックスを付けます。例:
driver.encoding=UTF8
これにより、encodingプロパティに値UTF8が、DriverManager.getConnection(url, driverProperties)メソッドを介してデータベースドライバーに渡されます。
POOLED – このDataSourceの実装は、JDBC接続オブジェクトをプールして、新しい接続インスタンスを作成するために必要な初期接続と認証時間を回避します。これは、同時Webアプリケーションで最速の応答を実現するための一般的なアプローチです。
上記の(UNPOOLED)プロパティに加えて、POOLEDデータソースを構成するために使用できるプロパティが他にも多数あります。
poolMaximumActiveConnections– これは、任意の時点で存在できるアクティブ(つまり、使用中の)接続の数です。デフォルト:10poolMaximumIdleConnections– 任意の時点で存在できるアイドル接続の数。poolMaximumCheckoutTime– これは、接続がプールから強制的に返されるまでに「チェックアウト」できる時間です。デフォルト:20000ms(つまり、20秒)poolTimeToWait– これは、プールがログステータスを出力し、接続の取得に異常に時間がかかっている場合に再試行する機会を与える低レベルの設定です(プールの構成が誤っている場合に、永久にサイレントで失敗することを避けるため)。デフォルト:20000ms(つまり、20秒)poolMaximumLocalBadConnectionTolerance– これは、任意のスレッドで取得された不良接続の許容度に関する低レベルの設定です。スレッドが不良接続を取得した場合、有効な別の接続を取得するために再試行するチャンスがまだあります。ただし、再試行回数は、poolMaximumIdleConnectionsとpoolMaximumLocalBadConnectionToleranceの合計を超えてはなりません。デフォルト:3(3.4.5以降)poolPingQuery– Pingクエリは、接続が正常に機能しており、リクエストを受け入れる準備ができていることを検証するためにデータベースに送信されます。デフォルトは「PINGクエリは設定されていません」であり、ほとんどのデータベースドライバーは適切なエラーメッセージで失敗します。poolPingEnabled– これは、pingクエリを有効または無効にします。有効にした場合は、poolPingQueryプロパティに有効なSQLステートメント(できれば非常に高速なもの)を設定する必要もあります。デフォルト:false。poolPingConnectionsNotUsedFor– これは、poolPingQueryが使用される頻度を構成します。これは、データベース接続の一般的なタイムアウトに合わせて設定し、不要なpingを回避できます。デフォルト:0(つまり、すべての接続は毎回pingされます - ただし、poolPingEnabledがtrueの場合に限ります)。
JNDI – このDataSourceの実装は、DataSourceを一元的にまたは外部で構成し、その参照をJNDIコンテキストに配置する可能性のあるEJBやアプリケーションサーバーなどのコンテナで使用することを目的としています。このDataSource構成に必要なプロパティは2つだけです。
initial_context– このプロパティは、InitialContextからのコンテキストルックアップに使用されます(つまり、initialContext.lookup(initial_context))。このプロパティはオプションであり、省略された場合、data_sourceプロパティがInitialContextに対して直接検索されます。data_source– これは、DataSourceのインスタンスへの参照が見つかるコンテキストパスです。これは、initial_contextルックアップによって返されるコンテキストに対して、またはinitial_contextが提供されていない場合はInitialContextに対して直接検索されます。
他のDataSource構成と同様に、プロパティにenv.というプレフィックスを付けることで、プロパティをInitialContextに直接送信できます。例:
env.encoding=UTF8
これにより、encodingプロパティに値UTF8が、インスタンス化時にInitialContextのコンストラクターに送信されます。
インターフェースorg.apache.ibatis.datasource.DataSourceFactoryを実装することで、サードパーティのDataSourceをプラグインできます。
public interface DataSourceFactory {
void setProperties(Properties props);
DataSource getDataSource();
}
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactoryは、新しいデータソースアダプターを構築するためのスーパークラスとして使用できます。たとえば、C3P0をプラグインするために必要なコードは次のとおりです。
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
public C3P0DataSourceFactory() {
this.dataSource = new ComboPooledDataSource();
}
}
セットアップするには、MyBatisに呼び出させる各セッターメソッドのプロパティを追加します。以下に、PostgreSQLデータベースに接続するサンプル構成を示します。
<dataSource type="org.myproject.C3P0DataSourceFactory">
<property name="driver" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql:mydb"/>
<property name="username" value="postgres"/>
<property name="password" value="root"/>
</dataSource>
databaseIdProvider
MyBatisは、データベースベンダーに応じて異なるステートメントを実行できます。マルチDBベンダーのサポートは、マッピングされたステートメントのdatabaseId属性に基づいています。MyBatisは、databaseId属性がないか、現在の属性と一致するdatabaseIdを持つすべてのステートメントをロードします。同じステートメントがdatabaseIdの有無にかかわらず見つかった場合、後者は破棄されます。マルチベンダーのサポートを有効にするには、mybatis-config.xmlファイルにdatabaseIdProviderを次のように追加します。
<databaseIdProvider type="DB_VENDOR" />
DB_VENDOR実装databaseIdProviderは、DatabaseMetaData#getDatabaseProductName()によって返されるStringをdatabaseIdとして設定します。通常、その文字列が長すぎることと、同じ製品の異なるバージョンが異なる値を返す可能性があるため、次のようにプロパティを追加して、より短いものに変換することをお勧めします。
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
プロパティが提供されている場合、DB_VENDOR databaseIdProviderは、返されたデータベース製品名で見つかった最初のキーに対応するプロパティ値を検索するか、一致するプロパティがない場合は「null」を検索します。この場合、getDatabaseProductName()が「Oracle(DataDirect)」を返す場合、databaseIdは「oracle」に設定されます。
インターフェースorg.apache.ibatis.mapping.DatabaseIdProviderを実装し、それをmybatis-config.xmlに登録することで、独自のDatabaseIdProviderを構築できます。
public interface DatabaseIdProvider {
default void setProperties(Properties p) { // Since 3.5.2, changed to default method
// NOP
}
String getDatabaseId(DataSource dataSource) throws SQLException;
}
mappers
上記の構成要素でMyBatisの動作が構成されたので、マッピングされたSQLステートメントを定義する準備ができました。しかし、まず、それらを見つける場所をMyBatisに伝える必要があります。Javaは、この点で自動検出の良い手段を提供していないため、マッピングファイルを見つける場所をMyBatisに伝えるのが最善の方法です。クラスパス相対リソース参照、完全修飾URL参照(file:///URLを含む)、クラス名、またはパッケージ名を使用できます。例:
<!-- Using classpath relative resources -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- Using url fully qualified paths -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- Using mapper interface classes -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- Register all interfaces in a package as mappers -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
これらのステートメントは、ここからどこに行くかをMyBatisに伝えるだけです。残りの詳細は各SQLマッピングファイルにあり、それはまさに次のセクションで説明することです。
MyBatis