一、核心配置文件概述
首先给出xml核心配置文件的组成部分,核心配置文件由头部生命和配置两个部分所组成,头部声明包含一下内容
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
配置部分由configuration标签包裹,里面可以包含以下内容
- properties(属性)
- settings(设置)
- typeAliases(类型别名)
- typeHandlers(类型处理器)
- objectFactory(对象工厂)
- plugins(插件)
- environments(环境配置)
7.1. environment(环境变量
7.2 transactionManager(事务管理器) - dataSource(数据源)
- databaseIdProvider(数据库厂商标识) mappers(映射器)
下面就对这些内容分别进行阐述
二、属性properties
2.1、数据动态读取
2.1.1、数据读取方式
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件(*.properties文件)中配置这些属性,也可以在 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 文件中对应的值来替换。
通过构造函数的方式进行设置也是可以的
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
// ... 或者 ...
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);
这里的reader是Reader类型的变量,environment是字符串,props是Properties类型的变量
2.1.2、数据读取优先级
三种设置方式的优先级为构造方法 > 文件中读取的 > property标签设置的,优先级低的值将被优先级高的值覆盖
2.2、占位符默认值的设置
从 MyBatis 3.4.2 开始,你可以为占位符指定一个默认值,采用的是冒号加默认值的方式。例如
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${username:ut_user}"/> <!-- 如果属性 'username' 没有被配置,'username' 属性的值将为 'ut_user' -->
</dataSource>
如果要使用这个属性,需要在properties标签内部添加一个property标签进行配置,这是因为设定默认值的属性默认是关闭的
<properties resource="org/mybatis/example/config.properties">
<!-- ... -->
<property name="org.apache.ibatis.parsing.PropertyParser.enable-default-value" value="true"/> <!-- 启用默认值特性 -->
</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="?:"/> <!-- 修改默认值的分隔符 -->
</properties>
<dataSource type="POOLED">
<!-- ... -->
<property name="username" value="${db:username?:ut_user}"/>
</dataSource>
二、设置settings
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
三、类型别名typeAliases
3.1、自定义类型别名
类型别名可为 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 {
...
}
3.2、Java 类型内建的类型别名
四、类处理器typeHandlers
类处理器主要是将JDBC取出的数据库类型转为Java类型
Mybatis也支持用户自定义类处理器。详情见官方文档。
五、对象工厂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支持引入一些第三方的插件,比如分页插件
<plugins>
<!-- com.github.pagehelper.PageInterceptor -->
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="helperDialect" value="mysql" />
<property name="reasonable" value="true" />
</plugin>
</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 的核心模块。 这些都是更底层的类和方法,所以使用插件的时候要特别当心。通过 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();
public Object intercept(Invocation invocation) throws Throwable {
// implement pre processing if need
Object returnObject = invocation.proceed();
// implement post processing if need
return returnObject;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}
七、环境配置 environments
7.1、environments标签
环境主要针对将SQL映射应用到多种数据库之中,每一个数据库都拥有一个SqlSession实例,创建不同环境的SqlSession对象需要传递Environment实例对象,如下所示
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);
Environment对象可以通过Java语句进行构造
public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {
if (id == null) {
throw new IllegalArgumentException("Parameter 'id' must not be null");
} else if (transactionFactory == null) {
throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null");
} else {
this.id = id;
if (dataSource == null) {
throw new IllegalArgumentException("Parameter 'dataSource' must not be null");
} else {
this.transactionFactory = transactionFactory;
this.dataSource = dataSource;
}
}
}
也可以通过配置的方式进行,下面给出了environment配置的典型例子
<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>
environments标签内可以包含多个environment标签,每个标签代表了一种环境,通过设置enviroments标签中的default选项,可以设置默认的环境的id。每个environment标签的id通过id进行设置。
7.2、内部的environment标签
每一个environment标签又包括两个部分,分别是事务管理器transactionManager和数据源dataSource,下面就针对每一个小的标签进行阐述。
7.2.1、事务管理器transactionManager
事务管理器有两种类型,分别是JDBC和MANAGED
- JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
- MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
值得注意的是,如果使用了Spring + Mybatis框架,则不需要配置事务管理器,因为Spring自带的管理器会配置前面的事务管理器。
这两种事务管理器都不需要配置任何的property参数,因为TransactionFactory接口的setProperties方法是空的。如果想要对参数进行设置,可以采用同名实现类重写方法来实现。
7.2.2、数据源dataSource
dataSource数据源首先需要配置type,type有三种内建的数据类型,分别是POOLED、UNPOOLED、JNDI,下面对这三种内建数据类型进行介绍
UNPOOLDE
顾名思义就是不使用连接池的一种方式,可以用于连接可用性要求不高的业务,UNPOOLED需要配置五种属性
- driver – 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。作为可选项,你也可以传递属性给数据库驱动。只需在属性名加上“driver.”前缀即可,例如:driver.encoding=UTF8
- url – 这是数据库的 JDBC URL 地址。
- username – 登录数据库的用户名。
- password – 登录数据库的密码。
- defaultTransactionIsolationLevel – 默认的连接事务隔离级别。
- defaultNetworkTimeout – 等待数据库操作完成的默认网络超时时间(单位:毫秒)
其中driver、url、username、password四个属性通常来讲是必须的
POOLED
使用连接池的方式,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求,除了上述四个属性之外,还有这几种属性可以进行配置
- 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或者应用服务器等的设置,用的比较少,这里就不再赘述了,用的时候可以看官方文档
八、数据库厂商标识 databaseIdProvider
MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载带有匹配当前数据库 databaseId 属性和所有不带 databaseId 属性的语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。 为支持多厂商特性,只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:
<databaseIdProvider type="DB_VENDOR" />
databaseIdProvider 对应的 DB_VENDOR 实现会将 databaseId 设置为 DatabaseMetaData#getDatabaseProductName() 返回的字符串。 由于通常情况下这些字符串都非常长,而且相同产品的不同版本会返回不同的值,你可能想通过设置属性别名来使其变短:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
设置好了之后就可以在映射配置文件当中通过设置databaseId来选择不同的sql语句了,比如下面这样
<select id="SelectTime" resultType="String" databaseId="mysql">
SELECT NOW() FROM dual
</select>
<select id="SelectTime" resultType="String" databaseId="oracle">
SELECT 'oralce'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') FROM dual
</select>
程序会根据启用的数据库的不同来选择不同的语句执行
九、映射器Mappers
我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。映射器Mappers标签内可以有多个Mapper标签来指向不同的资源,资源的指向方式有4种:类路径资源引用、完全限定资源路径引用、实现类内容引用、实现类的包的内容引用,后两种主要针对注解形式的sql语句,这个后面会说到,先展示以下这四种资源的引入方式
<!-- 使用相对于类路径的资源引用 -->
<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>
十、总结
可以看到,environments标签和mappers标签两项是必须拥有的,因为他们一个关乎与数据库连接,一个关乎从数据库得到数据并将其映射到domain对象当中,而其他标签下的内容要么存在有默认值,不必要的时候可以不设置,要么属于辅助性的一些内容。
因此在编写Mybatis核心配置文件的过程中可以先写environments标签以便Mybatis与数据库连接,再编写mappers标签完成映射,其他标签按需取。