这是我们在上一篇文章中用到的:
MyBatis 的 XML 配置文件包含了影响 MyBatis 行为甚深的设置和属性信息。XML 文档的高层级结构如下:
- configuration 配置
- properties 属性
- settings 设置
- typeAliases 类型命名
- typeHandlers 类型处理器
- objectFactory 对象工厂
- plugins 插件
- environments 环境
- 映射器
properties
这些是外部化的,可替代的属性,这些属性也可以配置在典型的 Java 属性配置文件中,或者通过 properties 元素的子元素来传递。例如:
其中的属性就可以在整个配置文件中使用,使用可替换的属性来实现动态配置。比如:
这个例子中的 username 和 password 将会由 properties 元素中设置的值来替换。driver 和url 属性将会从包含进来的 config.properties 文件中的值来替换。这里提供很多配置的选项。
属性也可以被传递到 SqlSessionBuilder.build()方法中。例如:
SqlSessionFactory factory =
sqlSessionFactoryBuilder.build(reader, props);
// ... or ...
SqlSessionFactory factory =
sqlSessionFactoryBuilder.build(reader, environment, props);
如果在这些地方,属性多于一个的话,MyBatis 按照如下的顺序加载它们:
- 在 properties 元素体内指定的属性首先被读取。
- 从类路径下资源或 properties 元素的 url 属性中加载的属性第二被读取,它会覆盖已经存在的完全一样的属性。
- 作为方法参数传递的属性最后被读取,它也会覆盖任一已经存在的完全一样的属性,这些属性可能是从 properties 元素体内和资源/url 属性中加载的。因此,最高优先级的属性是那些作为方法参数的,然后是资源/url 属性,最后是 properties元素中指定的属性。
Settings
这些是极其重要的调整,它们会修改 MyBatis 在运行时的行为方式。下面这个表格描述了设置信息,它们的含义和默认值。
一个设置信息元素的示例,完全的配置如下所示:
typeAliases
类型别名是为 Java 类型命名一个短的名字。它只和 XML 配置有关,只用来减少类完全限定名的多余部分。例如:
使用这个配置,“Blog”可以任意用来替代“domain.blog.Blog”所使用的地方。
对于普通的 Java 类型,有许多内建的类型别名。它们都是大小写不敏感的,由于重载的名字,要注意原生类型的特殊处理。
无论是 MyBatis 在预处理语句中设置一个参数,还是从结果集中取出一个值时,类型处理器被用来将获取的值以合适的方式转换成 Java 类型。下面这个表格描述了默认的类型处理器。
作为代码存储(而不是索引)。
你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。要这样做的话,简单实现 TypeHandler 接口(org.mybatis.type),然后映射新的类型处理器类到Java 类型,还有可选的一个 JDBC 类型。例如:
// ExampleTypeHandler.java
public class ExampleTypeHandler implements TypeHandler {
public void setParameter(PreparedStatement ps, int i, Object
parameter,JdbcType jdbcType) throws SQLException {
ps.setString(i, (String) parameter);
}
public Object getResult(ResultSet rs, String columnName)
throws SQLException {
return rs.getString(columnName);
}
public Object getResult(CallableStatement cs, int columnIndex)
throws SQLException {
return cs.getString(columnIndex);
}
}
// MapperConfig.xml
使用这样的类型处理器将会覆盖已经存在的处理 Java 的 String 类型属性和 VARCHAR参数及结果的类型处理器。要注意 MyBatis 不会审视数据库元信息来决定使用哪种类型,所以你必须在参数和结果映射中指定那是 VARCHAR 类型的字段,来绑定到正确的类型处理器上。这是因为 MyBatis 直到语句被执行都不知道数据类型的这个现实导致的。
objectFactory
MyBatis 每次创建结果对象新的实例时,它使用一个 ObjectFactory 实例来完成。如果参数映射存在,默认的 ObjectFactory 不比使用默认构造方法或带参数的构造方法实例化目标类做的工作多。如果你想重写默认的 ObjectFactory,你可以创建你自己的。比如:
// ExampleObjectFactory.java
public class ExampleObjectFactory extends DefaultObjectFactory {
public Object create(Class type) {
return super.create(type);
}
public Object create(Class type,List constructorArgTypes,
List
// MapperConfig.xml
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 的核心。这是低层次的类和方法,要谨慎使用插件。
使用插件是它们提供的非常简单的力量。简单实现拦截器接口,要确定你想拦截的指定签名。
// 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) {
}
}
// MapperConfig.xml
上面的插件将会拦截在 Executor 实例中所有的“update”方法调用,它也是负责低层次映射语句执行的内部对象。
environments
MyBatis 可以配置多种环境。这会帮助你将 SQL 映射应用于多种数据库之中。例如,你也许为开发要设置不同的配置,测试和生产环境。或者你可能有多种生产级数据库却共享相同的模式,所以你会想对不同数据库使用相同的 SQL 映射。这种用例是很多的。
要记得一个很重要的问题:你可以配置多种环境,但你只能为每个SqlSessionFactory实例选择一个。
所以,如果你想连接两个数据库,你需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,你就需要三个实例,以此类推。记忆起来很简单:
个 每个数据库对应一个 SqlSessionFactory
为了明确创建哪种环境,你可以将它作为可选的参数传递给 SqlSessionFactoryBuilder。
可以接受环境配置的两个方法签名是:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,
environment,properties);
如果环境被忽略,那么默认环境将会被加载,如下进行:
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader,properties);
环境元素定义了如何配置环境。
注意这里的关键部分:
默认的环境 ID(比如:default=”development”)。
每个 environment 元素定义的环境 ID(比如:id=”development”)。
事务管理器的配置(比如:type=”JDBC”)。
覆盖配置类
除了用插件来修改 MyBatis 核心行为之外,你也可以完全覆盖配置类。简单扩展它,
然后覆盖其中的任意方法,之后传递它到 sqlSessionFactoryBuilder.build(myConfig)方法
的调用。这可能会严重影响 MyBatis 的行为,所以要小心。
数据源的配置(比如:type=”POOLED”)。
默认的环境和环境 ID 是自我解释的。你可以使用你喜欢的名称来命名,只要确定默认
的要匹配其中之一。
transactionManager
在 MyBatis 中有两种事务管理器类型(也就是 type=”[JDBC|MANAGED]”):
JDBC – 这个配置直接简单使用了 JDBC 的提交和回滚设置。它依赖于从数据源得
到的连接来管理事务范围。
MANAGED – 这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让
容器来管理事务的整个生命周期(比如 Spring 或 JEE 应用服务器的上下文)。默认
情况下它会关闭连接。然而一些容器并不希望这样,因此如果你需要从连接中停止
它,将 closeConnection 属性设置为 false。例如:
这两种事务管理器都不需要任何属性。然而它们都是类型别名,要替换使用它们,你需
要放置将你自己的类的完全限定名或类型别名,它们引用了你对 TransacFactory 接口的实现
类。
public interface TransactionFactory {
void setProperties(Properties props);
Transaction newTransaction(Connection conn, boolean autoCommit);
}
任何在 XML 中配置的属性在实例化之后将会被传递给 setProperties()方法。你的实现类
需要创建一个事务接口的实现,这个接口也很简单:
public interface Transaction {
Connection getConnection();
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
}
使用这两个接口,你可以完全自定义 MyBatis 对事务的处理。
dataSsource
dataSource 元素使用基本的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
许多 MyBatis 的应用程序将会按示例中的例子来配置数据源。然而它并不是必须的。
要知道为了方便使用延迟加载,数据源才是必须的。
有三种内建的数据源类型(也就是 type=”???”):
UNPOOLED – 这个数据源的实现是每次被请求时简单打开和关闭连接。它有一点慢,
这是对简单应用程序的一个很好的选择,因为它不需要及时的可用连接。不同的数据库对这
个的表现也是不一样的,所以对某些数据库来说配置数据源并不重要,这个配置也是闲置的。
UNPOOLED 类型的数据源仅仅用来配置以下 5 种属性:
driver – 这是 JDBC 驱动的 Java 类的完全限定名(如果你的驱动包含的有,它也
不是数据源类)。
url – 这是数据库的 JDBC URL 地址。
username – 登录数据库的用户名。
password – 登录数据库的密码。
defaultTransactionIsolationLevel – 默认的连接事务隔离级别。
作为可选项,你可以传递数据库驱动的属性。要这样做,属性的前缀是以“driver.”开
头的,例如:
driver.encoding=UTF8
这 样 就 会 传 递 以 值 “ UTF8 ” 来 传 递 “ encoding ” 属 性 , 它 是 通 过
DriverManager.getConnection(url,driverProperties)方法传递给数据库驱动。
POOLED – 这是 JDBC 连接对象的数据源连接池的实现,用来避免创建新的连接实例
时必要的初始连接和认证时间。这是一种当前 Web 应用程序用来快速响应请求很流行的方
法。
除了上述(UNPOOLED)的属性之外,还有很多属性可以用来配置 POOLED 数据源:
poolMaximumActiveConnections – 在任意时间存在的活动(也就是正在使用)连
接的数量。默认值:10
poolMaximumIdleConnections – 任意时间存在的空闲连接数。
poolMaximumCheckoutTime – 在被强制返回之前,池中连接被检查的时间。默认
值:20000 毫秒(也就是 20 秒)
poolTimeToWait – 这是给连接池一个打印日志状态机会的低层次设置,还有重新
尝试获得连接,这些情况下往往需要很长时间(为了避免连接池没有配置时静默失
败)。默认值:20000 毫秒(也就是 20 秒)
poolPingQuery – 发送到数据的侦测查询,用来验证连接是否正常工作,并且准备
接受请求。默认是“NO PING QUERY SET”,这会引起许多数据库驱动连接由一
个错误信息而导致失败。
poolPingEnabled – 这是开启或禁用侦测查询。如果开启,你必须用一个合法的
SQL 语句(最好是很快速的)设置 poolPingQuery 属性。默认值:false。
poolPingConnectionsNotUsedFor – 这是用来配置 poolPingQuery 多次时间被用一
次。这可以被设置匹配标准的数据库连接超时时间,来避免不必要的侦测。默认值:
0(也就是所有连接每一时刻都被侦测-但仅仅当 poolPingEnabled 为 true 时适用)。
JNDI – 这个数据源的实现是为了使用如 Spring 或应用服务器这类的容器,容器可以集
中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。这个数据源配置只需要两个属
性:
initial_context – 这 个 属 性 用 来 从 初 始 上 下 文 中 寻 找 环 境 ( 也 就 是
initialContext.lookup(initial——context))。这是个可选属性,如果被忽略,那么
data_source 属性将会直接以 initialContext 为背景再次寻找。
data_source – 这是引用数据源实例位置的上下文的路径。它会以由 initial_context
查询返回的环境为背景来查找,如果 initial_context 没有返回结果时,直接以初始
上下文为环境来查找。
和其他数据源配置相似,它也可以通过名为“env.”的前缀直接向初始上下文发送属性。
比如:
env.encoding=UTF8
在初始化之后,这就会以值“UTF8”向初始上下文的构造方法传递名为“encoding”
的属性。
mappers
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要定义 SQL 映射语句了。
但是,首先我们需要告诉 MyBatis 到哪里去找到这些语句。Java 在这方面没有提供一个很好
的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的
资源引用,或者字符表示,或 url 引用的完全限定名(包括 file:///URLs)。例如:
// 使用相对于类路径的资源
// 使用完全限定路径