From 57ed37ba832a7fb4cecbbace756e772dbff2b83d Mon Sep 17 00:00:00 2001 From: Kazuki Shimizu Date: Sat, 6 Jun 2020 20:48:45 +0900 Subject: [PATCH 1/3] Support global configuration for applying sql provider type when omit on annotation --- .../builder/annotation/ProviderSqlSource.java | 7 +- .../ibatis/builder/xml/XMLConfigBuilder.java | 1 + .../apache/ibatis/session/Configuration.java | 22 +++++++ .../CustomizedSettingsMapperConfig.xml | 1 + .../ibatis/builder/XmlConfigBuilderTest.java | 9 +++ .../sqlprovider/SqlProviderTest.java | 66 +++++++++++++++++++ 6 files changed, 104 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/ibatis/builder/annotation/ProviderSqlSource.java b/src/main/java/org/apache/ibatis/builder/annotation/ProviderSqlSource.java index 11701352bba..38f132b4fc5 100644 --- a/src/main/java/org/apache/ibatis/builder/annotation/ProviderSqlSource.java +++ b/src/main/java/org/apache/ibatis/builder/annotation/ProviderSqlSource.java @@ -100,7 +100,7 @@ public ProviderSqlSource(Configuration configuration, Annotation provider, Class this.mapperMethod = mapperMethod; Lang lang = mapperMethod == null ? null : mapperMethod.getAnnotation(Lang.class); this.languageDriver = configuration.getLanguageDriver(lang == null ? null : lang.value()); - this.providerType = getProviderType(provider, mapperMethod); + this.providerType = getProviderType(configuration, provider, mapperMethod); candidateProviderMethodName = (String) provider.annotationType().getMethod("method").invoke(provider); if (candidateProviderMethodName.length() == 0 && ProviderMethodResolver.class.isAssignableFrom(this.providerType)) { @@ -235,11 +235,14 @@ private String invokeProviderMethod(Object... args) throws Exception { return sql != null ? sql.toString() : null; } - private Class getProviderType(Annotation providerAnnotation, Method mapperMethod) + private Class getProviderType(Configuration configuration, Annotation providerAnnotation, Method mapperMethod) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class type = (Class) providerAnnotation.annotationType().getMethod("type").invoke(providerAnnotation); Class value = (Class) providerAnnotation.annotationType().getMethod("value").invoke(providerAnnotation); if (value == void.class && type == void.class) { + if (configuration.getDefaultSqlProviderType() != null) { + return configuration.getDefaultSqlProviderType(); + } throw new BuilderException("Please specify either 'value' or 'type' attribute of @" + providerAnnotation.annotationType().getSimpleName() + " at the '" + mapperMethod.toString() + "'."); diff --git a/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java b/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java index a9ca156c647..0ba8bdbea7f 100644 --- a/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java +++ b/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java @@ -269,6 +269,7 @@ private void settingsElement(Properties props) { configuration.setLogPrefix(props.getProperty("logPrefix")); configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory"))); configuration.setShrinkWhitespacesInSql(booleanValueOf(props.getProperty("shrinkWhitespacesInSql"), false)); + configuration.setDefaultSqlProviderType(resolveClass(props.getProperty("defaultSqlProviderType"))); } private void environmentsElement(XNode context) throws Exception { diff --git a/src/main/java/org/apache/ibatis/session/Configuration.java b/src/main/java/org/apache/ibatis/session/Configuration.java index c1cd04d1ecc..e7bee1fd802 100644 --- a/src/main/java/org/apache/ibatis/session/Configuration.java +++ b/src/main/java/org/apache/ibatis/session/Configuration.java @@ -118,6 +118,7 @@ public class Configuration { protected String logPrefix; protected Class logImpl; protected Class vfsImpl; + protected Class defaultSqlProviderType; protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION; protected JdbcType jdbcTypeForNull = JdbcType.OTHER; protected Set lazyLoadTriggerMethods = new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString")); @@ -243,6 +244,27 @@ public void setVfsImpl(Class vfsImpl) { } } + /** + * GEt an applying type when omit a type on sql provider annotation(e.g. {@link org.apache.ibatis.annotations.SelectProvider}). + * + * @return the default type for sql provider annotation + * @since 3.5.6 + */ + public Class getDefaultSqlProviderType() { + return defaultSqlProviderType; + } + + /** + * Sets an applying type when omit a type on sql provider annotation(e.g. {@link org.apache.ibatis.annotations.SelectProvider}). + * + * @param defaultSqlProviderType + * the default type for sql provider annotation + * @since 3.5.6 + */ + public void setDefaultSqlProviderType(Class defaultSqlProviderType) { + this.defaultSqlProviderType = defaultSqlProviderType; + } + public boolean isCallSettersOnNulls() { return callSettersOnNulls; } diff --git a/src/test/java/org/apache/ibatis/builder/CustomizedSettingsMapperConfig.xml b/src/test/java/org/apache/ibatis/builder/CustomizedSettingsMapperConfig.xml index 2aa631d2d45..fce0aeb1474 100644 --- a/src/test/java/org/apache/ibatis/builder/CustomizedSettingsMapperConfig.xml +++ b/src/test/java/org/apache/ibatis/builder/CustomizedSettingsMapperConfig.xml @@ -55,6 +55,7 @@ + diff --git a/src/test/java/org/apache/ibatis/builder/XmlConfigBuilderTest.java b/src/test/java/org/apache/ibatis/builder/XmlConfigBuilderTest.java index ef1851130dd..059b3d8a3d9 100644 --- a/src/test/java/org/apache/ibatis/builder/XmlConfigBuilderTest.java +++ b/src/test/java/org/apache/ibatis/builder/XmlConfigBuilderTest.java @@ -101,6 +101,7 @@ void shouldSuccessfullyLoadMinimalXMLConfigFile() throws Exception { assertNull(config.getConfigurationFactory()); assertThat(config.getTypeHandlerRegistry().getTypeHandler(RoundingMode.class)).isInstanceOf(EnumTypeHandler.class); assertThat(config.isShrinkWhitespacesInSql()).isFalse(); + assertThat(config.getDefaultSqlProviderType()).isNull(); } } @@ -196,6 +197,7 @@ void shouldSuccessfullyLoadXMLConfigFile() throws Exception { assertThat(config.getVfsImpl().getName()).isEqualTo(JBoss6VFS.class.getName()); assertThat(config.getConfigurationFactory().getName()).isEqualTo(String.class.getName()); assertThat(config.isShrinkWhitespacesInSql()).isTrue(); + assertThat(config.getDefaultSqlProviderType().getName()).isEqualTo(MySqlProvider.class.getName()); assertThat(config.getTypeAliasRegistry().getTypeAliases().get("blogauthor")).isEqualTo(Author.class); assertThat(config.getTypeAliasRegistry().getTypeAliases().get("blog")).isEqualTo(Blog.class); @@ -304,4 +306,11 @@ void propertiesSpecifyResourceAndUrlAtSameTime() { .hasMessageContaining("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other."); } + static class MySqlProvider { + @SuppressWarnings("unused") + public static String provideSql() { + return "SELECT 1"; + } + } + } diff --git a/src/test/java/org/apache/ibatis/submitted/sqlprovider/SqlProviderTest.java b/src/test/java/org/apache/ibatis/submitted/sqlprovider/SqlProviderTest.java index 45352134210..d6b36d270e5 100644 --- a/src/test/java/org/apache/ibatis/submitted/sqlprovider/SqlProviderTest.java +++ b/src/test/java/org/apache/ibatis/submitted/sqlprovider/SqlProviderTest.java @@ -30,9 +30,11 @@ import java.util.Map; import org.apache.ibatis.BaseDataTest; +import org.apache.ibatis.annotations.InsertProvider; import org.apache.ibatis.annotations.DeleteProvider; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.SelectProvider; +import org.apache.ibatis.annotations.UpdateProvider; import org.apache.ibatis.binding.MapperMethod; import org.apache.ibatis.builder.BuilderException; import org.apache.ibatis.builder.annotation.ProviderContext; @@ -661,6 +663,70 @@ void keepBackwardCompatibilityOnDeprecatedConstructorWithAnnotation() throws NoS assertEquals("SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS", sqlSource.getBoundSql(null).getSql()); } + @Test + void omitTypeWhenSpecifyDefaultType() throws NoSuchMethodException { + Class mapperType = DefaultSqlProviderMapper.class; + Configuration configuration = new Configuration(); + configuration.setDefaultSqlProviderType(DefaultSqlProviderMapper.SqlProvider.class); + { + Method mapperMethod = mapperType.getMethod("select", int.class); + String sql = new ProviderSqlSource(configuration, mapperMethod.getAnnotation(SelectProvider.class), mapperType, + mapperMethod).getBoundSql(1).getSql(); + assertEquals("select name from foo where id = ?", sql); + } + { + Method mapperMethod = mapperType.getMethod("insert", String.class); + String sql = new ProviderSqlSource(configuration, mapperMethod.getAnnotation(InsertProvider.class), mapperType, + mapperMethod).getBoundSql("Taro").getSql(); + assertEquals("insert into foo (name) values(?)", sql); + } + { + Method mapperMethod = mapperType.getMethod("update", int.class, String.class); + String sql = new ProviderSqlSource(configuration, mapperMethod.getAnnotation(UpdateProvider.class), mapperType, + mapperMethod).getBoundSql(Collections.emptyMap() ).getSql(); + assertEquals("update foo set name = ? where id = ?", sql); + } + { + Method mapperMethod = mapperType.getMethod("delete", int.class); + String sql = new ProviderSqlSource(configuration, mapperMethod.getAnnotation(DeleteProvider.class), mapperType, + mapperMethod).getBoundSql(Collections.emptyMap() ).getSql(); + assertEquals("delete from foo where id = ?", sql); + } + } + + public interface DefaultSqlProviderMapper { + + @SelectProvider + String select(int id); + + @InsertProvider + void insert(String name); + + @UpdateProvider + void update(int id, String name); + + @DeleteProvider + void delete(int id); + + class SqlProvider { + + public static String provideSql(ProviderContext c) { + switch (c.getMapperMethod().getName()) { + case "select" : + return "select name from foo where id = #{id}"; + case "insert" : + return "insert into foo (name) values(#{name})"; + case "update" : + return "update foo set name = #{name} where id = #{id}"; + default: + return "delete from foo where id = #{id}"; + } + } + + } + + } + public interface ErrorMapper { @SelectProvider(type = ErrorSqlBuilder.class, method = "methodNotFound") void methodNotFound(); From 638a00c9c91cf87a740d9b9e680acefc7685e273 Mon Sep 17 00:00:00 2001 From: Kazuki Shimizu Date: Sun, 7 Jun 2020 15:07:57 +0900 Subject: [PATCH 2/3] Fix typo Related with gh-1951 --- src/main/java/org/apache/ibatis/session/Configuration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/apache/ibatis/session/Configuration.java b/src/main/java/org/apache/ibatis/session/Configuration.java index e7bee1fd802..eb0558c292d 100644 --- a/src/main/java/org/apache/ibatis/session/Configuration.java +++ b/src/main/java/org/apache/ibatis/session/Configuration.java @@ -245,7 +245,7 @@ public void setVfsImpl(Class vfsImpl) { } /** - * GEt an applying type when omit a type on sql provider annotation(e.g. {@link org.apache.ibatis.annotations.SelectProvider}). + * Gets an applying type when omit a type on sql provider annotation(e.g. {@link org.apache.ibatis.annotations.SelectProvider}). * * @return the default type for sql provider annotation * @since 3.5.6 From 9df34f5db8205d8076f3f79575e44ba0241b7cc3 Mon Sep 17 00:00:00 2001 From: Kazuki Shimizu Date: Sun, 7 Jun 2020 16:54:34 +0900 Subject: [PATCH 3/3] Update document for gh-1951 --- src/site/es/xdoc/configuration.xml | 16 ++++++++++++++++ src/site/es/xdoc/java-api.xml | 26 +++++++++++++++++++++++++- src/site/ja/xdoc/configuration.xml | 15 +++++++++++++++ src/site/ja/xdoc/java-api.xml | 26 +++++++++++++++++++++++++- src/site/ko/xdoc/configuration.xml | 16 ++++++++++++++++ src/site/ko/xdoc/java-api.xml | 26 +++++++++++++++++++++++++- src/site/xdoc/configuration.xml | 16 ++++++++++++++++ src/site/xdoc/java-api.xml | 27 ++++++++++++++++++++++++++- src/site/zh/xdoc/configuration.xml | 16 ++++++++++++++++ src/site/zh/xdoc/java-api.xml | 30 +++++++++++++++++++++++++++++- 10 files changed, 209 insertions(+), 5 deletions(-) diff --git a/src/site/es/xdoc/configuration.xml b/src/site/es/xdoc/configuration.xml index ae995427efb..3d7e30e01dc 100644 --- a/src/site/es/xdoc/configuration.xml +++ b/src/site/es/xdoc/configuration.xml @@ -561,6 +561,22 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ false + + + defaultSqlProviderType + + + Specifies an sql provider class that holds provider method (Since 3.5.6). + This class apply to the type(or value) attribute on sql provider annotation(e.g. @SelectProvider), + when these attribute was omitted. + + + A type alias or fully qualified class name + + + Not set + +

diff --git a/src/site/es/xdoc/java-api.xml b/src/site/es/xdoc/java-api.xml index 9e14192618c..8a7bdda71a5 100644 --- a/src/site/es/xdoc/java-api.xml +++ b/src/site/es/xdoc/java-api.xml @@ -480,7 +480,8 @@ void rollback(boolean force) via the ProviderContext(available since MyBatis 3.4.5 or later) as method argument.(In MyBatis 3.4 or later, it's allow multiple parameters) Atributos: value, type y method. El atributo value y type es el nombre completamente cualificado de una clase - (The type attribute is alias for value, you must be specify either one). + (The type attribute is alias for value, you must be specify either one. + But both attributes can be omit when specify the defaultSqlProviderType as global configuration). El method es el nombre un método de dicha clase (Since 3.5.1, you can omit method attribute, the MyBatis will resolve a target method via the ProviderMethodResolver interface. @@ -635,6 +636,29 @@ class UserSqlProvider implements ProviderMethodResolver { } }]]> +

This example shows usage that share an sql provider class to all mapper methods using global configuration(Available since 3.5.6):

+ + +

This example shows usage the default implementation of ProviderMethodResolver(available since MyBatis 3.5.1 or later):

getUsersByName(String name); diff --git a/src/site/ja/xdoc/configuration.xml b/src/site/ja/xdoc/configuration.xml index 2599dad7764..55f2f8921c9 100644 --- a/src/site/ja/xdoc/configuration.xml +++ b/src/site/ja/xdoc/configuration.xml @@ -586,6 +586,21 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ false + + + defaultSqlProviderType + + + SQLを提供するメソッドを保持するSQLプロバイダクラスを指定します(導入されたバージョン: 3.5.6)。 + ここで指定したクラスは、SQLプロバイダアノテーション(例: @SelectProvider)のtype(または value) 属性を省略した際に適用されます。 + + + タイプエイリアスまたは完全修飾クラス名 + + + 未指定 + +

diff --git a/src/site/ja/xdoc/java-api.xml b/src/site/ja/xdoc/java-api.xml index 42336527eaf..a9f79a77e09 100644 --- a/src/site/ja/xdoc/java-api.xml +++ b/src/site/ja/xdoc/java-api.xml @@ -491,7 +491,8 @@ void rollback(boolean force) なお、メソッド引数にはMapperメソッドの引数に渡したオブジェクトに加え、ProviderContext(MyBatis 3.4.5以降で利用可能)を介して「Mapperインタフェースの型」「Mapperメソッド」「データベースID」を渡すことができます。(MyBatis 3.4以降では、複数の引数を渡すことができます) キー: value, type, method. valuetype にはクラスオブジェクトを指定します - (typevalue の別名で、どちらか一方を指定する必要があります)。 + (typevalue の別名で、どちらか一方を指定する必要があります。 + ただし、グローバル設定としてdefaultSqlProviderTypeを指定している場合は両方とも省略することができます)。 method にはメソッド名を指定します (MyBatis 3.5.1以降では、method 属性を省略することができます。その際MyBatisは、ProviderMethodResolver インタフェースを介して対象メソッドの解決を試み、 対象メソッドが解決できない場合は、provideSqlという名前のメソッドを代替メソッドとして利用します)。 @@ -619,6 +620,29 @@ class UserSqlBuilder { } }]]> +

次のコードは、グローバル設定を利用して全てのマッパーメソッドで同じSQLプロバイダクラスを利用する例です。(3.5.6以降で利用可能)

+ + +

次のコードは、ProviderMethodResolver(MyBatis 3.5.1以降で利用可能)のデフォルト実装の利用例です。

getUsersByName(String name); diff --git a/src/site/ko/xdoc/configuration.xml b/src/site/ko/xdoc/configuration.xml index 6363b8c6a27..815387e5837 100644 --- a/src/site/ko/xdoc/configuration.xml +++ b/src/site/ko/xdoc/configuration.xml @@ -569,6 +569,22 @@ SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environ false + + + defaultSqlProviderType + + + Specifies an sql provider class that holds provider method (Since 3.5.6). + This class apply to the type(or value) attribute on sql provider annotation(e.g. @SelectProvider), + when these attribute was omitted. + + + A type alias or fully qualified class name + + + Not set + +

위 설정을 모두 사용한 setting 엘리먼트의 예제이다:

diff --git a/src/site/ko/xdoc/java-api.xml b/src/site/ko/xdoc/java-api.xml index 7961425e5d8..3051dd4e9d9 100644 --- a/src/site/ko/xdoc/java-api.xml +++ b/src/site/ko/xdoc/java-api.xml @@ -605,7 +605,8 @@ void rollback(boolean force) 매핑된 구문을 실행할 때 마이바티스는 클래스의 인스턴스를 만들고 메소드를 실행한다. Mapper 메서드의 인수인 "Mapper interface type" and "Database ID" 과 ProviderContext(Mybatis 3.4.5 부터) 를 이용한 "Mapper method" 로 전달 된 객체를 메서드 매개변수로 전달할 수 있다.(마이바티스 3.4이상에서는 복수 파라미터를 허용한다.) 사용가능한 속성들 : value, type, method. - value and type 속성은 클래스 (The type attribute is alias for value, you must be specify either one). + value and type 속성은 클래스 (The type attribute is alias for value, you must be specify either one. + But both attributes can be omit when specify the defaultSqlProviderType as global configuration). method 속성은 메소드명이다 (Since 3.5.1, you can omit method attribute, the MyBatis will resolve a target method via the ProviderMethodResolver interface. @@ -749,6 +750,29 @@ class UserSqlBuilder { } }]]> +

This example shows usage that share an sql provider class to all mapper methods using global configuration(Available since 3.5.6):

+ + +

This example shows usage the default implementation of ProviderMethodResolver(available since MyBatis 3.5.1 or later):

getUsersByName(String name); diff --git a/src/site/xdoc/configuration.xml b/src/site/xdoc/configuration.xml index 3a9121ae2ec..fdd5e285f37 100644 --- a/src/site/xdoc/configuration.xml +++ b/src/site/xdoc/configuration.xml @@ -648,6 +648,22 @@ SqlSessionFactory factory = false + + + defaultSqlProviderType + + + Specifies an sql provider class that holds provider method (Since 3.5.6). + This class apply to the type(or value) attribute on sql provider annotation(e.g. @SelectProvider), + when these attribute was omitted. + + + A type alias or fully qualified class name + + + Not set + +

diff --git a/src/site/xdoc/java-api.xml b/src/site/xdoc/java-api.xml index eb38a085ab2..ac37f62c6f7 100644 --- a/src/site/xdoc/java-api.xml +++ b/src/site/xdoc/java-api.xml @@ -525,7 +525,8 @@ void rollback(boolean force) (In MyBatis 3.4 or later, it's allow multiple parameters) Attributes: value, type, method and databaseId. The value and type attribute is a class - (The type attribute is alias for value, you must be specify either one). + (The type attribute is alias for value, you must be specify either one. + But both attributes can be omit when specify the defaultSqlProviderType as global configuration). The method is the name of the method on that class (Since 3.5.1, you can omit method attribute, the MyBatis will resolve a target method via the ProviderMethodResolver interface. @@ -672,6 +673,29 @@ class UserSqlBuilder { } }]]> +

This example shows usage that share an sql provider class to all mapper methods using global configuration(Available since 3.5.6):

+ + +

This example shows usage the default implementation of ProviderMethodResolver(available since MyBatis 3.5.1 or later):

getUsersByName(String name); @@ -691,6 +715,7 @@ class UserSqlProvider implements ProviderMethodResolver { } }]]> +

This example shows usage the databaseId attribute on the statement annotation(Available since 3.5.5):

+ + + defaultSqlProviderType + + + Specifies an sql provider class that holds provider method (Since 3.5.6). + This class apply to the type(or value) attribute on sql provider annotation(e.g. @SelectProvider), + when these attribute was omitted. + + + A type alias or fully qualified class name + + + Not set + +

diff --git a/src/site/zh/xdoc/java-api.xml b/src/site/zh/xdoc/java-api.xml index be48288f40c..e7b192ed4f3 100644 --- a/src/site/zh/xdoc/java-api.xml +++ b/src/site/zh/xdoc/java-api.xml @@ -464,7 +464,12 @@ try (SqlSession session = sqlSessionFactory.openSession()) {         - 允许构建动态 SQL。这些备选的 SQL 注解允许你指定返回 SQL 语句的类和方法,以供运行时执行。(从 MyBatis 3.4.6 开始,可以使用 CharSequence 代替 String 来作为返回类型)。当执行映射语句时,MyBatis 会实例化注解指定的类,并调用注解指定的方法。你可以通过 ProviderContext 传递映射方法接收到的参数、"Mapper interface type" 和 "Mapper method"(仅在 MyBatis 3.4.5 以上支持)作为参数。(MyBatis 3.4 以上支持传入多个参数)属性:typemethodtype 属性用于指定类名。method 用于指定该类的方法名(从版本 3.5.1 开始,可以省略 method 属性,MyBatis 将会使用 ProviderMethodResolver 接口解析方法的具体实现。如果解析失败,MyBatis 将会使用名为 provideSql 的降级实现)。提示 接下来的“SQL 语句构建器”一章将会讨论该话题,以帮助你以更清晰、更便于阅读的方式构建动态 SQL。 + 允许构建动态 SQL。这些备选的 SQL 注解允许你指定返回 SQL 语句的类和方法,以供运行时执行。(从 MyBatis 3.4.6 开始,可以使用 CharSequence 代替 String 来作为返回类型)。当执行映射语句时,MyBatis 会实例化注解指定的类,并调用注解指定的方法。你可以通过 ProviderContext 传递映射方法接收到的参数、"Mapper interface type" 和 "Mapper method"(仅在 MyBatis 3.4.5 以上支持)作为参数。(MyBatis 3.4 以上支持传入多个参数) + 属性:valuetypemethoddatabaseId。 + value and type 属性用于指定类名 + (The type attribute is alias for value, you must be specify either one. + But both attributes can be omit when specify the defaultSqlProviderType as global configuration)。 + method 用于指定该类的方法名(从版本 3.5.1 开始,可以省略 method 属性,MyBatis 将会使用 ProviderMethodResolver 接口解析方法的具体实现。如果解析失败,MyBatis 将会使用名为 provideSql 的降级实现)。提示 接下来的“SQL 语句构建器”一章将会讨论该话题,以帮助你以更清晰、更便于阅读的方式构建动态 SQL。 The databaseId(Available since 3.5.5), in case there is a configured DatabaseIdProvider, the MyBatis will use a provider method with no databaseId attribute or with a databaseId that matches the current one. If found with and without the databaseId the latter will be discarded. @@ -581,6 +586,29 @@ class UserSqlBuilder { } }]]> +

This example shows usage that share an sql provider class to all mapper methods using global configuration(Available since 3.5.6):

+ + +

以下例子展示了 ProviderMethodResolver(3.5.1 后可用)的默认实现使用方法: