MyBatis公式チュートリアルおよびソースコード解析-mapperマッピングファイル
キャッシュ
1.公式文書
MyBatisには、構成とカスタマイズを容易にする強力なクエリーキャッシュ機能が含まれています.MyBatis 3のキャッシュ実装の多くの改良は、より強力で構成しやすいように実現されています.
デフォルトではキャッシュがオンになっていません.ローカルのsessionキャッシュに加えて、変現を強化し、ループ依存を処理する必要があります.2次キャッシュを開くには、SQLマッピングファイルに行を追加する必要があります.
文字通りそうです.この単純な文の効果は次のとおりです.
・マッピング文ファイル内のすべてのselect文がキャッシュされます.
・文ファイル内のすべてのinsertをマッピングすると、update文とdelete文がキャッシュをリフレッシュします.
・キャッシュは、Least Recently Used(LRU、最近最も使用されていない)アルゴリズムを使用して回収される.
・キャッシュは、リフレッシュ間隔なしのno Flush Intervalなどのスケジュールに従って、任意の時間順序でリフレッシュされません.
・キャッシュは、クエリ・メソッドが何を返すかにかかわらず、リスト・セットまたはオブジェクトの1024個の参照を格納する.
・キャッシュはread/write(読み取り/書き込み可能)のキャッシュと見なされ、オブジェクト検索が共有されていないことを意味し、他の呼び出し者またはスレッドが行う潜在的な変更に干渉することなく、呼び出し者によって安全に変更されることを意味する.
これらのアトリビュートはすべて、キャッシュ要素のアトリビュートで変更できます.例:
このより高度な構成では、FIFOキャッシュが作成され、60秒ごとにリフレッシュされ、結果オブジェクトまたはリストの512個の参照が格納され、返されるオブジェクトは読み取り専用とみなされるため、異なるスレッド内の呼び出し者間で変更すると競合します.
利用可能な回収ポリシーは次のとおりです.
・LRU–最も最近使用されていないオブジェクトを削除します.
・FIFO–オブジェクトがキャッシュに入る順に削除します.
・SOFT–ソフトリファレンス:ゴミ回収器の状態とソフトリファレンス規則に基づくオブジェクトを除去します.
・WEAK–弱参照:ゴミ収集器の状態と弱参照規則に基づくオブジェクトをより積極的に除去する.
デフォルトはLRUです.
flushInterval(リフレッシュ間隔)は、任意の正の整数に設定でき、合理的なミリ秒形式の期間を表す.デフォルトでは、リフレッシュ間隔が設定されていない、つまり、キャッシュが文のみを呼び出すときにリフレッシュされます.
size(参照数)は、キャッシュされたオブジェクトの数と実行環境で使用可能なメモリリソースの数を記憶する任意の正の整数に設定できます.既定値は1024です.
readOnly(読み取り専用)アトリビュートはtrueまたはfalseに設定できます.読み取り専用キャッシュは、すべての呼び出し元にキャッシュオブジェクトの同じインスタンスを返します.したがって、これらのオブジェクトは変更できません.これにより、重要なパフォーマンスのメリットが得られます.読み書き可能なキャッシュは、キャッシュ・オブジェクトのコピー(シーケンス化)を返します.これは遅くなりますが、安全なので、デフォルトはfalseです.
2.ソース解析
キャッシュの解析は比較的簡単で、mybatisは構成に基づいてcacheオブジェクトを生成し、configurationに格納します.各マッピングプロファイルには1つのcacheしかありません.複数を構成する場合は1つ目のみ有効です.
新しいキャッシュを定義するだけでなく、cache-refを利用して他のマッピングファイル構成のキャッシュを直接使用することもできます.
の解析はの前にあるので、currentCacheオブジェクトは後者を選択します.
Sql文ブロック
1.公式文書
この要素は、他の文に含めることができる再利用可能なSQLコードセグメントを定義するために使用できます.静的に(パラメータをロード)パラメータ化することができる.異なる属性値は、含むインスタンスによって変化する.例:
このSQLフラグメントは、次のような他の文に含めることができます.
属性値は、含まれるrefid属性または含まれる文の属性値に使用できます.たとえば、次のようにします.
2.ソース解析
Sql文ブロックとマッピング文は解析時にDatabaseIdによって区別され、databaseIdとdatabaseIdを持たない同じ文が同時に見つかった場合、後者は破棄されます.これにより、文を構成するときに異なるデータベースに異なる文を構成できます.
最後のsqlコードブロックがノード全体をMapに格納するのは、sqlが動的多重化を実現できるため、sqlコードブロックの値を毎回再解析する必要があり、これらは次のマッピング文の解析部分で完了する.
マッピングステートメント
マッピング文は、Mapper構成の複雑な部分であり、sql文ブロックを埋め込むことができる一方で、動的Sqlもあります.
まずの解析を見てみましょう.公式ドキュメントにはにサブノードが含まれています.
ユーザーはのために異なる値を構成して動的多重化を実現することができ、を構成しなければ、MybatisはXMLプロファイルから探します.を対応するsql文に置き換えます.
次にの解析を行い、configurationのkeyGeneratorsに保存される特殊なマッピング文と見なすことができます.
最後にマッピング文の解析
以上のコードから,マッピング文は最終的にMapperBuilderAssistantによってMappedStatementオブジェクトに解析され,最後にこのプロセスがどのように実現されるかを見ることができる.
1.公式文書
MyBatisには、構成とカスタマイズを容易にする強力なクエリーキャッシュ機能が含まれています.MyBatis 3のキャッシュ実装の多くの改良は、より強力で構成しやすいように実現されています.
デフォルトではキャッシュがオンになっていません.ローカルのsessionキャッシュに加えて、変現を強化し、ループ依存を処理する必要があります.2次キャッシュを開くには、SQLマッピングファイルに行を追加する必要があります.
<cache/>
文字通りそうです.この単純な文の効果は次のとおりです.
・マッピング文ファイル内のすべてのselect文がキャッシュされます.
・文ファイル内のすべてのinsertをマッピングすると、update文とdelete文がキャッシュをリフレッシュします.
・キャッシュは、Least Recently Used(LRU、最近最も使用されていない)アルゴリズムを使用して回収される.
・キャッシュは、リフレッシュ間隔なしのno Flush Intervalなどのスケジュールに従って、任意の時間順序でリフレッシュされません.
・キャッシュは、クエリ・メソッドが何を返すかにかかわらず、リスト・セットまたはオブジェクトの1024個の参照を格納する.
・キャッシュはread/write(読み取り/書き込み可能)のキャッシュと見なされ、オブジェクト検索が共有されていないことを意味し、他の呼び出し者またはスレッドが行う潜在的な変更に干渉することなく、呼び出し者によって安全に変更されることを意味する.
これらのアトリビュートはすべて、キャッシュ要素のアトリビュートで変更できます.例:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
このより高度な構成では、FIFOキャッシュが作成され、60秒ごとにリフレッシュされ、結果オブジェクトまたはリストの512個の参照が格納され、返されるオブジェクトは読み取り専用とみなされるため、異なるスレッド内の呼び出し者間で変更すると競合します.
利用可能な回収ポリシーは次のとおりです.
・LRU–最も最近使用されていないオブジェクトを削除します.
・FIFO–オブジェクトがキャッシュに入る順に削除します.
・SOFT–ソフトリファレンス:ゴミ回収器の状態とソフトリファレンス規則に基づくオブジェクトを除去します.
・WEAK–弱参照:ゴミ収集器の状態と弱参照規則に基づくオブジェクトをより積極的に除去する.
デフォルトはLRUです.
flushInterval(リフレッシュ間隔)は、任意の正の整数に設定でき、合理的なミリ秒形式の期間を表す.デフォルトでは、リフレッシュ間隔が設定されていない、つまり、キャッシュが文のみを呼び出すときにリフレッシュされます.
size(参照数)は、キャッシュされたオブジェクトの数と実行環境で使用可能なメモリリソースの数を記憶する任意の正の整数に設定できます.既定値は1024です.
readOnly(読み取り専用)アトリビュートはtrueまたはfalseに設定できます.読み取り専用キャッシュは、すべての呼び出し元にキャッシュオブジェクトの同じインスタンスを返します.したがって、これらのオブジェクトは変更できません.これにより、重要なパフォーマンスのメリットが得られます.読み書き可能なキャッシュは、キャッシュ・オブジェクトのコピー(シーケンス化)を返します.これは遅くなりますが、安全なので、デフォルトはfalseです.
2.ソース解析
キャッシュの解析は比較的簡単で、mybatisは構成に基づいてcacheオブジェクトを生成し、configurationに格納します.各マッピングプロファイルには1つのcacheしかありません.複数を構成する場合は1つ目のみ有効です.
//XMLMapperBuilder
private void cacheElement(XNode context) throws Exception {
if (context != null) {
//
String type = context.getStringAttribute("type", "PERPETUAL");
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
String eviction = context.getStringAttribute("eviction", "LRU");
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
Long flushInterval = context.getLongAttribute("flushInterval");
Integer size = context.getIntAttribute("size");
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
boolean blocking = context.getBooleanAttribute("blocking", false);
Properties props = context.getChildrenAsProperties();
// builderAssistant
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}
//MapperBuilderAssistant
public Cache useNewCache(Class<? extends Cache> typeClass,
Class<? extends Cache> evictionClass,
Long flushInterval,
Integer size,
boolean readWrite,
boolean blocking,
Properties props) {
Cache cache = new CacheBuilder(currentNamespace)
.implementation(valueOrDefault(typeClass, PerpetualCache.class))
.addDecorator(valueOrDefault(evictionClass, LruCache.class))
.clearInterval(flushInterval)
.size(size)
.readWrite(readWrite)
.blocking(blocking)
.properties(props)
.build();
// cache configuration
configuration.addCache(cache);
// cache
currentCache = cache;
return cache;
}
新しいキャッシュを定義するだけでなく、cache-refを利用して他のマッピングファイル構成のキャッシュを直接使用することもできます.
<cache-ref namespace="com.someone.application.data.SomeMapper"/>
private void cacheRefElement(XNode context) {
if (context != null) {
// configuration
configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
try {
// cacheRefResolver , MapperBuilderAssistant useCacheRef
cacheRefResolver.resolveCacheRef();
} catch (IncompleteElementException e) {
configuration.addIncompleteCacheRef(cacheRefResolver);
}
}
}
public Cache useCacheRef(String namespace) {
if (namespace == null) {
throw new BuilderException("cache-ref element requires a namespace attribute.");
}
try {
unresolvedCacheRef = true;
Cache cache = configuration.getCache(namespace);
//cache ,
if (cache == null) {
throw new IncompleteElementException("No cache for namespace '" + namespace + "' could be found.");
}
// cache currentCache
currentCache = cache;
unresolvedCacheRef = false;
return cache;
} catch (IllegalArgumentException e) {
throw new IncompleteElementException("No cache for namespace '" + namespace + "' could be found.", e);
}
}
Sql文ブロック
1.公式文書
この要素は、他の文に含めることができる再利用可能なSQLコードセグメントを定義するために使用できます.静的に(パラメータをロード)パラメータ化することができる.異なる属性値は、含むインスタンスによって変化する.例:
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
このSQLフラグメントは、次のような他の文に含めることができます.
<select id="selectUsers" resultType="map">
select
<include refid="userColumns"><property name="alias" value="t1"/></include>,
<include refid="userColumns"><property name="alias" value="t2"/></include>
from some_table t1
cross join some_table t2</select>
属性値は、含まれるrefid属性または含まれる文の属性値に使用できます.たとえば、次のようにします.
<sql id="sometable">
${prefix}Table</sql>
<sql id="someinclude">
from
<include refid="${include_target}"/></sql>
<select id="select" resultType="map">
select
field1, field2, field3
<include refid="someinclude">
<property name="prefix" value="Some"/>
<property name="include_target" value="sometable"/>
</include></select>
2.ソース解析
Sql文ブロックとマッピング文は解析時にDatabaseIdによって区別され、databaseIdとdatabaseIdを持たない同じ文が同時に見つかった場合、後者は破棄されます.これにより、文を構成するときに異なるデータベースに異なる文を構成できます.
//XMLMapperBuilder
private void sqlElement(List<XNode> list) throws Exception {
// databaseIdProvider
if (configuration.getDatabaseId() != null) {
sqlElement(list, configuration.getDatabaseId());
}
sqlElement(list, null);
}
private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
for (XNode context : list) {
String databaseId = context.getStringAttribute("databaseId");
String id = context.getStringAttribute("id");
id = builderAssistant.applyCurrentNamespace(id, false);
// databaseId
if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
// ID
sqlFragments.put(id, context);
}
}
}
private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
// databaseIdProvider,
if (requiredDatabaseId != null) {
if (!requiredDatabaseId.equals(databaseId)) {
return false;
}
} else {
// databaseIdProvider, databaseId
if (databaseId != null) {
return false;
}
// ID databaseId ,
if (this.sqlFragments.containsKey(id)) {
XNode context = this.sqlFragments.get(id);
if (context.getStringAttribute("databaseId") != null) {
return false;
}
}
}
return true;
}
最後のsqlコードブロックがノード全体をMapに格納するのは、sqlが動的多重化を実現できるため、sqlコードブロックの値を毎回再解析する必要があり、これらは次のマッピング文の解析部分で完了する.
マッピングステートメント
マッピング文は、Mapper構成の複雑な部分であり、sql文ブロックを埋め込むことができる一方で、動的Sqlもあります.
//XMLMapperBuilder
private void buildStatementFromContext(List<XNode> list) {
if (configuration.getDatabaseId() != null) {
buildStatementFromContext(list, configuration.getDatabaseId());
}
buildStatementFromContext(list, null);
}
private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
for (XNode context : list) {
final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
try {
// XMLStatementBuilder
statementParser.parseStatementNode();
} catch (IncompleteElementException e) {
configuration.addIncompleteStatement(statementParser);
}
}
}
//XMLStatementBuilder
public void parseStatementNode() {
String id = context.getStringAttribute("id");
String databaseId = context.getStringAttribute("databaseId");
if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
return;
}
Integer fetchSize = context.getIntAttribute("fetchSize");
Integer timeout = context.getIntAttribute("timeout");
String parameterMap = context.getStringAttribute("parameterMap");
String parameterType = context.getStringAttribute("parameterType");
Class<?> parameterTypeClass = resolveClass(parameterType);
String resultMap = context.getStringAttribute("resultMap");
String resultType = context.getStringAttribute("resultType");
String lang = context.getStringAttribute("lang");
LanguageDriver langDriver = getLanguageDriver(lang);
Class<?> resultTypeClass = resolveClass(resultType);
String resultSetType = context.getStringAttribute("resultSetType");
StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
String nodeName = context.getNode().getNodeName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
// , flushCache userCache
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
boolean useCache = context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);
//1. sql (include)
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
includeParser.applyIncludes(context.getNode());
//2. selectKey
processSelectKeyNodes(id, parameterTypeClass, langDriver);
//3. SQL
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
String resultSets = context.getStringAttribute("resultSets");
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
KeyGenerator keyGenerator;
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? new Jdbc3KeyGenerator() : new NoKeyGenerator();
}
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
まず
ユーザーは
public void applyIncludes(Node source) {
Properties variablesContext = new Properties();
// XML property
Properties configurationVariables = configuration.getVariables();
if (configurationVariables != null) {
variablesContext.putAll(configurationVariables);
}
applyIncludes(source, variablesContext);
}
private void applyIncludes(Node source, final Properties variablesContext) {
// <include>
if (source.getNodeName().equals("include")) {
// fullContext ,
Properties fullContext;
String refid = getStringAttribute(source, "refid");
// refid ( refid="${include_target}" )
refid = PropertyParser.parse(refid, variablesContext);
Node toInclude = findSqlFragment(refid);
// <property>
Properties newVariablesContext = getVariablesContext(source, variablesContext);
//
if (!newVariablesContext.isEmpty()) {
// merge contexts
fullContext = new Properties();
fullContext.putAll(variablesContext);
fullContext.putAll(newVariablesContext);
} else {
// no new context - use inherited fully
fullContext = variablesContext;
}
// Sql ,toInclude <sql>
applyIncludes(toInclude, fullContext);
if (toInclude.getOwnerDocument() != source.getOwnerDocument()) {
toInclude = source.getOwnerDocument().importNode(toInclude, true);
}
// <include> <sql>
source.getParentNode().replaceChild(toInclude, source);
while (toInclude.hasChildNodes()) {
// <sql> sql
toInclude.getParentNode().insertBefore(toInclude.getFirstChild(), toInclude);
}
// <sql>
toInclude.getParentNode().removeChild(toInclude);
}else if (source.getNodeType() == Node.ELEMENT_NODE) {
NodeList children = source.getChildNodes();
for (int i=0; i<children.getLength(); i++) {
applyIncludes(children.item(i), variablesContext);
}
} else if (source.getNodeType() == Node.ATTRIBUTE_NODE && !variablesContext.isEmpty()) {
// replace variables in all attribute values
source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
} else if (source.getNodeType() == Node.TEXT_NODE && !variablesContext.isEmpty()) {
// replace variables ins all text nodes
source.setNodeValue(PropertyParser.parse(source.getNodeValue(), variablesContext));
}
}
以上のプロセスは、最終的に次に
private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
List<XNode> selectKeyNodes = context.evalNodes("selectKey");
// databaseId
if (configuration.getDatabaseId() != null) {
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
}
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
//
removeSelectKeyNodes(selectKeyNodes);
}
private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
for (XNode nodeToHandle : list) {
String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
String databaseId = nodeToHandle.getStringAttribute("databaseId");
if (databaseIdMatchesCurrent(id, databaseId, skRequiredDatabaseId)) {
parseSelectKeyNode(id, nodeToHandle, parameterTypeClass, langDriver, databaseId);
}
}
}
private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
String resultType = nodeToHandle.getStringAttribute("resultType");
Class<?> resultTypeClass = resolveClass(resultType);
StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));
//defaults
boolean useCache = false;
boolean resultOrdered = false;
KeyGenerator keyGenerator = new NoKeyGenerator();
Integer fetchSize = null;
Integer timeout = null;
boolean flushCache = false;
String parameterMap = null;
String resultMap = null;
ResultSetType resultSetTypeEnum = null;
SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
// <selectKey> select
SqlCommandType sqlCommandType = SqlCommandType.SELECT;
// ,<selectKey> MappedStatement ,
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);
id = builderAssistant.applyCurrentNamespace(id, false);
// configuration
MappedStatement keyStatement = configuration.getMappedStatement(id, false);
configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
}
最後にマッピング文の解析
public void parseStatementNode() {
//....
//3. SQL
// SqlSource , Sql
// langDriver , Sql ,
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
String resultSets = context.getStringAttribute("resultSets");
String keyProperty = context.getStringAttribute("keyProperty");
String keyColumn = context.getStringAttribute("keyColumn");
// KeyGenerator
KeyGenerator keyGenerator;
//keyStatementId <SelectKey> id , <SelectKey>
String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
if (configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
? new Jdbc3KeyGenerator() : new NoKeyGenerator();
}
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
resultSetTypeEnum, flushCache, useCache, resultOrdered,
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
以上のコードから,マッピング文は最終的にMapperBuilderAssistantによってMappedStatementオブジェクトに解析され,最後にこのプロセスがどのように実現されるかを見ることができる.
//MapperBuilderAssistant
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class<?> parameterType,
String resultMap,
Class<?> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
// cache-ref
if (unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
}
id = applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
// statementBuilder
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resulSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
MappedStatement statement = statementBuilder.build();
configuration.addMappedStatement(statement);
return statement;
}