Mybatis-XML配置

XML 映射配置文件

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置(settings)和属性(properties)信息。文档的顶层结构以下:html

properties

这些属性都是可外部配置且可动态替换的,既能够在典型的 Java 属性文件中配置,亦可经过 properties 元素的子元素来传递。例如:java

<properties resource="org/mybatis/example/config.properties"> <property name="username" value="dev_user"/> <property name="password" value="F2Fa3!33TYyg"/> </properties>

而后其中的属性就能够在整个配置文件中被用来替换须要动态配置的属性值。好比:        sql

<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()方法中。例如:apache

SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props); // ... or ... SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);

若是属性在不仅一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:缓存

  • 在 properties 元素体内指定的属性首先被读取。          
  • 而后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。          
  • 最后读取做为方法参数传递的属性,并覆盖已读取的同名属性。          

所以,经过方法参数传递的属性具备最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的是 properties 属性中指定的属性。服务器

  从MyBatis 3.4.2开始,你能够为占位符指定一个默认值。例如:        session

<dataSource type="POOLED"> <!-- ... --> <property name="username" value="${username:ut_user}"/> <!-- If 'username' property not present, username become 'ut_user' --> </dataSource>

这个特性默认是关闭的。若是你想为占位符指定一个默认值,   你应该添加一个指定的属性来开启这个特性。例如:        mybatis

<properties resource="org/mybatis/example/config.properties"> <!-- ... --> <property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- Enable this feature --> </properties>

提示 你可使用 ":" 做为属性键(e.g. db:username)           或者你也能够在sql定义中使用 OGNL 表达式的三元运算符(e.g. ${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 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。下表描述了设置中各项的意图、默认值等。

设置参数 描述 有效值 默认值
                cacheEnabled               全局地开启或关闭配置文件中的全部映射器已经配置的任何缓存。               true | false                               true              
                lazyLoadingEnabled               延迟加载的全局开关。当开启时,全部关联对象都会延迟加载。                特定关联关系中可经过设置fetchType属性来覆盖该项的开关状态。               true | false                               false              
                aggressiveLazyLoading               当开启时,任何方法的调用都会加载该对象的全部属性。不然,每一个属性会按需加载(参考lazyLoadTriggerMethods).                               true | false                               false (true in ≤3.4.1)              
                multipleResultSetsEnabled               是否容许单一语句返回多结果集(须要兼容驱动)。               true | false                               true              
                useColumnLabel               使用列标签代替列名。不一样的驱动在这方面会有不一样的表现,                具体可参考相关驱动文档或经过测试这两种不一样的模式来观察所用驱动的结果。               true | false                               true              
                useGeneratedKeys               容许 JDBC 支持自动生成主键,须要驱动兼容。                若是设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工做(好比 Derby)。               true | false                               False              
                autoMappingBehavior               指定 MyBatis 应如何自动映射列到字段或属性。                 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。                 FULL 会自动映射任意复杂的结果集(不管是否嵌套)。               NONE, PARTIAL, FULL                               PARTIAL              
                autoMappingUnknownColumnBehavior               指定发现自动映射目标未知列(或者未知属性类型)的行为。                
  • NONE: 不作任何反应
  • WARNING: 输出提醒日志 ('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN)
  • FAILING: 映射失败 (抛出 SqlSessionException)
                NONE, WARNING, FAILING                               NONE              
                defaultExecutorType               配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements);                 BATCH 执行器将重用语句并执行批量更新。               SIMPLE                REUSE                BATCH                               SIMPLE              
                defaultStatementTimeout               设置超时时间,它决定驱动等待数据库响应的秒数。                               任意正整数               Not Set (null)              
                defaultFetchSize               为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只能够在查询设置中被覆盖。                               任意正整数               Not Set (null)              
                safeRowBoundsEnabled               容许在嵌套语句中使用分页(RowBounds)。若是容许使用则设置为false。               true | false                               False              
                safeResultHandlerEnabled               容许在嵌套语句中使用分页(ResultHandler)。若是容许使用则设置为false。               true | false                               True              
                mapUnderscoreToCamelCase               是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的相似映射。               true | false                               False              
                localCacheScope                               MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。                默认值为 SESSION,这种状况下会缓存一个会话中执行的全部查询。                若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不一样调用将不会共享数据。               SESSION | STATEMENT                               SESSION              
                jdbcTypeForNull               当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。                某些驱动须要指定列的 JDBC 类型,多数状况直接用通常类型便可,好比 NULL、VARCHAR 或 OTHER。               JdbcType 常量. 大多都为: NULL, VARCHAR and OTHER                               OTHER              
                lazyLoadTriggerMethods               指定哪一个对象的方法触发一次延迟加载。                               用逗号分隔的方法列表。               equals,clone,hashCode,toString              
                defaultScriptingLanguage               指定动态 SQL 生成的默认语言。                               一个类型别名或彻底限定类名。               org.apache.ibatis.scripting.xmltags.XMLLanguageDriver              
                defaultEnumTypeHandler               指定 Enum 使用的默认 TypeHandler 。 (从3.4.5开始)               一个类型别名或彻底限定类名。               org.apache.ibatis.type.EnumTypeHandler              
                callSettersOnNulls               指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这对于有 Map.keySet() 依赖或 null 值初始化的时候是有用的。注意基本类型(int、boolean等)是不能设置成 null 的。               true | false                               false              
                returnInstanceForEmptyRow               当返回行的全部列都是空时,MyBatis默认返回null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集 (i.e. collectioin and association)。(从3.4.2开始)               true | false                               false              
                logPrefix               指定 MyBatis 增长到日志名称的前缀。                               任何字符串               Not set              
                logImpl               指定 MyBatis 所用日志的具体实现,未指定时将自动查找。               SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING                               Not set              
                proxyFactory               指定 Mybatis 建立具备延迟加载能力的对象所用到的代理工具。               CGLIB | JAVASSIST                               JAVASSIST (MyBatis 3.3 or above)              
                vfsImpl               指定VFS的实现                               自定义VFS的实现的类全限定名,以逗号分隔。               Not set              
                useActualParamName               容许使用方法签名中的名称做为语句参数名称。 为了使用该特性,你的工程必须采用Java 8编译,而且加上-parameters选项。(从3.4.1开始)               true | false                               true              
                configurationFactory               指定一个提供Configuration实例的类。 这个被返回的Configuration实例用来加载被反序列化对象的懒加载属性值。 这个类必须包含一个签名方法static Configuration getConfiguration(). (从 3.2.3 版本开始)               类型别名或者全类名.               Not set              

一个配置完整的 settings 元素的示例以下:        

<settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" 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="mapUnderscoreToCamelCase" value="false"/> <setting name="localCacheScope" value="SESSION"/> <setting name="jdbcTypeForNull" value="OTHER"/> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> </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 会在包名下面搜索须要的 Java Bean,好比:        

<typeAliases> <package name="domain.blog"/> </typeAliases>

每个在包 domain.blog 中的 Java Bean,在没有注解的状况下,会使用 Bean 的首字母小写的非限定类名来做为它的别名。          好比 domain.blog.Author 的别名为 author;如有注解,则别名为其注解值。看下面的例子:

@Alias("author") public class Author { ... }

这是一些为常见的 Java 类型内建的相应的类型别名。它们都是大小写不敏感的,须要注意的是由基本类型名称重复致使的特殊处理。

                别名                               映射的类型              
                _byte                               byte              
                _long                               long              
                _short                               short              
                _int                               int              
                _integer                               int              
                _double                               double              
                _float                               float              
                _boolean                               boolean              
                string                               String              
                byte                               Byte              
                long                               Long              
                short                               Short              
                int                               Integer              
                integer                               Integer              
                double                               Double              
                float                               Float              
                boolean                               Boolean              
                date                               Date              
                decimal                               BigDecimal              
                bigdecimal                               BigDecimal              
                object                               Object              
                map                               Map              
                hashmap                               HashMap              
                list                               List              
                arraylist                               ArrayList              
                collection                               Collection              
                iterator                               Iterator              

typeHandlers

不管是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,仍是从结果集中取出一个值时,          都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。

提示         从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API) 。        

                类型处理器               Java 类型               JDBC 类型              
BooleanTypeHandler               java.lang.Boolean, boolean               数据库兼容的 BOOLEAN              
ByteTypeHandler               java.lang.Byte, byte               数据库兼容的 NUMERICBYTE              
ShortTypeHandler               java.lang.Short, short               数据库兼容的 NUMERICSHORT INTEGER              
IntegerTypeHandler               java.lang.Integer, int               数据库兼容的 NUMERICINTEGER              
LongTypeHandler               java.lang.Long, long               数据库兼容的 NUMERICLONG INTEGER              
FloatTypeHandler               java.lang.Float, float               数据库兼容的 NUMERICFLOAT              
DoubleTypeHandler               java.lang.Double, double               数据库兼容的 NUMERICDOUBLE              
BigDecimalTypeHandler               java.math.BigDecimal               数据库兼容的 NUMERICDECIMAL              
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                               Enumeration Type                               VARCHAR-任何兼容的字符串类型,存储枚举的名称(而不是索引)              
EnumOrdinalTypeHandler                               Enumeration Type               任何兼容的 NUMERICDOUBLE 类型,存储枚举的索引(而不是名称)。              
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 or 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>

使用这个的类型处理器将会覆盖已经存在的处理 Java 的 String 类型属性和 VARCHAR 参数及结果的类型处理器。          要注意 MyBatis 不会窥探数据库元信息来决定使用哪一种类型,因此你必须在参数和结果映射中指明那是 VARCHAR 类型的字段,          以使其可以绑定到正确的类型处理器上。          这是由于:MyBatis 直到语句被执行才清楚数据类型。        

          经过类型处理器的泛型,MyBatis 能够得知该类型处理器处理的 Java 类型,不过这种行为能够经过两种方法改变:        

  • 在类型处理器的配置元素(typeHandler element)上增长一个 javaType 属性(好比:javaType="String");          
  • 在类型处理器的类上(TypeHandler class)增长一个 @MappedTypes 注解来指定与其关联的 Java 类型列表。            若是在 javaType 属性中也同时指定,则注解方式将被忽略。          

能够经过两种方式来指定被关联的 JDBC 类型:

  •             在类型处理器的配置元素上增长一个 jdbcType 属性(好比:jdbcType="VARCHAR");          
  • 在类型处理器的类上(TypeHandler class)增长一个 @MappedJdbcTypes 注解来指定与其关联的 JDBC 类型列表。            若是在 jdbcType 属性中也同时指定,则注解方式将被忽略。          

          当决定在ResultMap中使用某一TypeHandler时,此时java类型是已知的(从结果类型中得到),可是JDBC类型是未知的。   所以Mybatis使用javaType=[TheJavaType], jdbcType=null的组合来选择一个TypeHandler。   这意味着使用@MappedJdbcTypes注解能够限制TypeHandler的范围,同时除非显式的设置,不然TypeHandler在ResultMap中将是无效的。   若是但愿在ResultMap中使用TypeHandler,那么设置@MappedJdbcTypes注解的includeNullJdbcType=true便可。   然而从Mybatis 3.4.0开始,若是只有一个注册的TypeHandler来处理Java类型,那么它将是ResultMap使用Java类型时的默认值(即便没有includeNullJdbcType=true)。        

最后,可让 MyBatis 为你查找类型处理器:

<!-- mybatis-config.xml --> <typeHandlers> <package name="org.mybatis.example"/> </typeHandlers>

注意在使用自动检索(autodiscovery)功能的时候,只能经过注解方式来指定 JDBC 的类型。

你能够建立一个可以处理多个类的泛型类型处理器。为了使用泛型类型处理器,          须要增长一个接受该类的 class 做为参数的构造器,这样在构造一个类型处理器的时候 MyBatis 就会传入一个具体的类。

//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; } ...

EnumTypeHandlerEnumOrdinalTypeHandler 都是泛型类型处理器(generic TypeHandlers),          咱们将会在接下来的部分详细探讨。

处理枚举类型

若想映射枚举类型 Enum,则须要从 EnumTypeHandler 或者 EnumOrdinalTypeHandler 中选一个来使用。

好比说咱们想存储取近似值时用到的舍入模式。默认状况下,MyBatis 会利用 EnumTypeHandler 来把 Enum 值转换成对应的名字。

注意 EnumTypeHandler 在某种意义上来讲是比较特别的,其余的处理器只针对某个特定的类,而它不一样,它会处理任意继承了 Enum 的类。        

不过,咱们可能不想存储名字,相反咱们的 DBA 会坚持使用整形值代码。那也同样垂手可得:          在配置文件中把 EnumOrdinalTypeHandler 加到 typeHandlers 中便可,          这样每一个 RoundingMode 将经过他们的序数值来映射成对应的整形。        

<!-- mybatis-config.xml --> <typeHandlers> <typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/> </typeHandlers>

可是怎样能将一样的 Enum 既映射成字符串又映射成整形呢?

          自动映射器(auto-mapper)会自动地选用 EnumOrdinalTypeHandler 来处理,          因此若是咱们想用普通的 EnumTypeHandler,就必需要显式地为那些 SQL 语句设置要使用的类型处理器。        

(下一节才开始介绍映射器文件,若是你是首次阅读该文档,你可能须要先跳过这里,过会再来看。)

<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/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 语句强制使用 resultMap 来代替 resultType

对象工厂(objectFactory)

MyBatis 每次建立结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。          默认的对象工厂须要作的仅仅是实例化目标类,要么经过默认构造方法,要么在参数映射存在的时候经过参数构造方法来实例化。          若是想覆盖对象工厂的默认行为,则能够经过建立本身的对象工厂来实现。好比:

// ExampleObjectFactory.java public class ExampleObjectFactory extends DefaultObjectFactory { public Object create(Class type) { return super.create(type); } public Object create(Class type, List<Class> constructorArgTypes, List<Object> constructorArgs) { return super.create(type, constructorArgTypes, constructorArgs); } public void setProperties(Properties properties) { super.setProperties(properties); } 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 接口很简单,它包含两个建立用的方法,一个是处理默认构造方法的,另一个是处理带参数的构造方法的。          最后,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 的核心模块。          这些都是更低层的类和方法,因此使用插件的时候要特别小心。

经过 MyBatis 提供的强大机制,使用插件是很是简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名便可。

// ExamplePlugin.java @Intercepts({@Signature( type= Executor.class, method = "update", args = {MappedStatement.class,Object.class})}) public class ExamplePlugin implements Interceptor { public Object intercept(Invocation invocation) throws Throwable { return invocation.proceed(); } public Object plugin(Object target) { return Plugin.wrap(target, this); } public void setProperties(Properties properties) { } }
<!-- mybatis-config.xml --> <plugins> <plugin interceptor="org.mybatis.example.ExamplePlugin"> <property name="someProperty" value="100"/> </plugin> </plugins>

上面的插件将会拦截在 Executor 实例中全部的 “update” 方法调用,          这里的 Executor 是负责执行低层映射语句的内部对象。

提示           覆盖配置类        

除了用插件来修改 MyBatis 核心行为以外,还能够经过彻底覆盖配置类来达到目的。只需继承后覆盖其中的每一个方法,再把它传递到 SqlSessionFactoryBuilder.build(myConfig) 方法便可。再次重申,这可能会严重影响 MyBatis 的行为,务请慎之又慎。

配置环境(environments)

MyBatis 能够配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中,          现实状况下有多种理由须要这么作。例如,开发、测试和生产环境须要有不一样的配置;或者共享相同 Schema 的多个生产数据库,          想使用相同的 SQL 映射。许多相似的用例。

不过要记住:尽管能够配置多个环境,每一个 SqlSessionFactory 实例只能选择其一。        

          因此,若是你想链接两个数据库,就须要建立两个 SqlSessionFactory 实例,每一个数据库对应一个。而若是是三个数据库,就须要三个实例,依此类推,记起来很简单:        

  • 每一个数据库对应一个 SqlSessionFactory 实例                       

为了指定建立哪一种环境,只要将它做为可选的参数传递给 SqlSessionFactoryBuilder 便可。能够接受环境配置的两个方法签名是:        

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 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>

注意这里的关键点:        

  • 默认的环境 ID(好比:default="development")。          
  •             每一个 environment 元素定义的环境 ID(好比:id="development")。          
  •             事务管理器的配置(好比:type="JDBC")。          
  •             数据源的配置(好比:type="POOLED")。          

默认的环境和环境 ID 是自解释的,所以一目了然。你能够对环境随意命名,但必定要保证默认的环境 ID 要匹配其中一个环境 ID。        

事务管理器(transactionManager)        

在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”):

  • JDBC – 这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源获得的链接来管理事务做用域。          
  • MANAGED – 这个配置几乎没作什么。它历来不提交或回滚一个链接,而是让容器来管理事务的整个生命周期(好比 JEE 应用服务器的上下文)。            默认状况下它会关闭链接,然而一些容器并不但愿这样,所以须要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。例如:            
    <transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>

提示若是你正在使用 Spring + MyBatis,则没有必要配置事务管理器,          由于 Spring 模块会使用自带的管理器来覆盖前面的配置。        

          这两种事务管理器类型都不须要任何属性。它们不过是类型别名,换句话说,你可使用 TransactionFactory 接口的实现类的彻底限定名或类型别名代替它们。        

public interface TransactionFactory { void setProperties(Properties props); 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; }

使用这两个接口,你能够彻底自定义 MyBatis 对事务的处理。

数据源(dataSource)        

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 链接对象的资源。

  • 许多 MyBatis 的应用程序会按示例中的例子来配置数据源。虽然这是可选的,但为了使用延迟加载,数据源是必须配置的。          

有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):

UNPOOLED– 这个数据源的实现只是每次被请求时打开和关闭链接。虽然有点慢,但对于在数据库链接可用性方面没有过高要求的简单应用程序来讲,是一个很好的选择。          不一样的数据库在性能方面的表现也是不同的,对于某些数据库来讲,使用链接池并不重要,这个配置就很适合这种情形。UNPOOLED 类型的数据源仅仅须要配置如下 5 种属性:

  • driver – 这是 JDBC 驱动的 Java 类的彻底限定名(并非 JDBC 驱动中可能包含的数据源类)。          
  • url – 这是数据库的 JDBC URL 地址。          
  • username – 登陆数据库的用户名。          
  • password – 登陆数据库的密码。          
  • defaultTransactionIsolationLevel – 默认的链接事务隔离级别。          

做为可选项,你也能够传递属性给数据库驱动。要这样作,属性的前缀为“driver.”,例如:        

  • driver.encoding=UTF8

这将经过 DriverManager.getConnection(url,driverProperties) 方法传递值为 UTF8encoding 属性给数据库驱动。        

POOLED– 这种数据源的实现利用“池”的概念将 JDBC 链接对象组织起来,避免了建立新的链接实例时所必需的初始化和认证时间。          这是一种使得并发 Web 应用快速响应请求的流行处理方式。        

除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源:

  • poolMaximumActiveConnections – 在任意时间能够存在的活动(也就是正在使用)链接数量,默认值:10          
  • poolMaximumIdleConnections – 任意时间可能存在的空闲链接数。          
  • poolMaximumCheckoutTime – 在被强制返回以前,池中链接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)          
  • poolTimeToWait – 这是一个底层设置,若是获取链接花费了至关长的时间,链接池会打印状态日志并从新尝试获取一个链接(避免在误配置的状况下一直安静的失败),默认值:20000 毫秒(即 20 秒)。          
  • poolMaximumLocalBadConnectionTolerance – 这是一个关于坏链接容忍度的底层设置,            做用于每个尝试从缓存池获取链接的线程. 若是这个线程获取到的是一个坏的链接,那么这个数据源容许这个线程尝试从新获取一个新的链接,可是这个从新尝试的次数不该该超过 poolMaximumIdleConnections             与 poolMaximumLocalBadConnectionTolerance 之和。 默认值:3 (新增于 3.4.5)          
  • poolPingQuery – 发送到数据库的侦测查询,用来检验链接是否正常工做并准备接受请求。默认是“NO PING QUERY SET”,这会致使多数数据库驱动失败时带有一个恰当的错误消息。          
  • poolPingEnabled – 是否启用侦测查询。若开启,须要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度很是快的 SQL 语句),默认值:false。          
  • poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的频率。能够被设置为和数据库链接超时时间同样,来避免没必要要的侦测,默认值:0(即全部链接每一时刻都被侦测 — 固然仅当 poolPingEnabled 为 true 时适用)。          

JNDI – 这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器能够集中或在外部配置数据源,而后放置一个 JNDI 上下文的引用。这种数据源配置只须要两个属性:        

  • initial_context – 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,若是忽略,那么 data_source 属性将会直接从 InitialContext 中寻找。          
  • data_source – 这是引用数据源实例位置的上下文的路径。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则直接在 InitialContext 中查找。          

和其余数据源配置相似,能够经过添加前缀“env.”直接把属性传递给初始上下文。好比:        

  • env.encoding=UTF8

这就会在初始上下文(InitialContext)实例化时往它的构造方法传递值为 UTF8encoding 属性。        

          你能够经过实现接口 org.apache.ibatis.datasource.DataSourceFactory 来使用第三方数据源:        

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 调用的 setter 方法在配置文件中增长对应的属性。下面是一个能够链接至 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 能够根据不一样的数据库厂商执行不一样的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。           MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的全部语句。          若是同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。          为支持多厂商特性只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 便可:

<databaseIdProvider type="DB_VENDOR" />

这里的 DB_VENDOR 会经过 DatabaseMetaData#getDatabaseProductName() 返回的字符串进行设置。          因为一般状况下这个字符串都很是长并且相同产品的不一样版本会返回不一样的值,因此最好经过设置属性别名来使其变短,以下:

<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 { void setProperties(Properties p); String getDatabaseId(DataSource dataSource) throws SQLException; }

映射器(mappers)

既然 MyBatis 的行为已经由上述元素配置完了,咱们如今就要定义 SQL 映射语句了。可是首先咱们须要告诉 MyBatis 到哪里去找到这些语句。           Java 在自动查找这方面没有提供一个很好的方法,因此最佳的方式是告诉 MyBatis 到哪里去找映射文件。你可使用相对于类路径的资源引用,          或彻底限定资源定位符(包括 file:/// 的 URL),或类名和包名等。例如:

<!-- 使用相对于类路径的资源引用 --> <mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper resource="org/mybatis/builder/BlogMapper.xml"/> <mapper resource="org/mybatis/builder/PostMapper.xml"/> </mappers>
<!-- 使用彻底限定资源定位符(URL) --> <mappers> <mapper url="file:///var/mappers/AuthorMapper.xml"/> <mapper url="file:///var/mappers/BlogMapper.xml"/> <mapper url="file:///var/mappers/PostMapper.xml"/> </mappers>
<!-- 使用映射器接口实现类的彻底限定类名 --> <mappers> <mapper class="org.mybatis.builder.AuthorMapper"/> <mapper class="org.mybatis.builder.BlogMapper"/> <mapper class="org.mybatis.builder.PostMapper"/> </mappers>
<!-- 将包内的映射器接口实现所有注册为映射器 --> <mappers> <package name="org.mybatis.builder"/> </mappers>

这些配置会告诉了 MyBatis 去哪里找映射文件,剩下的细节就应该是每一个 SQL 映射文件了,也就是接下来咱们要讨论的。