####使用 XML 配置 MyBatis
Mybatis 最关键的组成部分是 SqlSessionFactory,我们可以从中获取 SqlSession,并执行映射的 SQL 语句。
SqlSessionFactory 对象可以通过基于 XML 的配置信息或者 Java API 创建。
构建 SqlSessionFactory 最常见的方式是基于 XML 配置的构造方式。下面的 mybatis-config.xml 展示了一个典型的 MyBatis 配置文件的样子:
配置文件示例
<configuration>
<typeAliases>
<typeAlias alias="Student" type="xx.mybatis3.domain.Student" />
<package name="xx.mybatis3.domain" />
</typeAliases>
<typeHandlers>
<typeHandler handler="xx.mybatis3.typehandlers.PhoneTypeHandler" />
<package name="xx.mybatis3.typehandlers" />
</typeHandlers>
<environments default="development">
<environment id="development">
<transacionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
<environment id="production">
<transactionManager type="MANAGED" />
<dataSource type="JNDI">
<property name="data_source" value="java:comp/jdbc/MyBatisDemoDS" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="xx/mybatis3/mappers/StudentMapper.xml" />
<mapper url="file:///E:/xx/mapper/StudentMapper.xml" />
<mapper class="xx.mybatis3.mapper.StudentMapper" />
</mappers>
</configuration>
Mybatis 支持配置多个 dataSource 环境,可以将应用部署到不同的环境上,如 DEV(开发环境),TEST(测试环境),QA(质量评估环境),UAT(用户验收环境),PRODUCTION(生产环境),可以通过将默认 environment 值设置成想要的 environment id值。
在上述的配置中,默认的环境 environment 被设置成 development。当需要将程序部署到生产服务器上时,不需要修改什么配置,只需要将 environments default 的值设置成生产环境的 environment id 属性的值即可。
将 <environments default="development">修改成<environments default="production">
有时候,我们可能需要在相同的应用下使用多个数据库。比如我们可能有 SHOPPING-CART 数据库来存储所有的订单明细:使用 REPORTS 数据库存储订单明细的合计,用作报告。
如果你的应用需要连接多个数据库,你需要将每个数据库配置成独立的环境,并且为每一个数据库创建一个 SqlSessionFactory。
environment 配置
<environments default="shoppingcart">
<environment id="shoppingcart">
<transactionManager type="MANAGED" />
<dataSource type="JNDI">
<property name="data_source" value="java:comp/jdbc/ShoppingcartDS" />
</dataSource>
</environment>
<environment id="reports">
<transationManager type="MANAGED" />
<dataSource type="JNDI">
<property name="data_source" value="java:comp/jdbc/ReportsDS" />
</dataSource>
</environment>
</environments>
接下来为每个环境创建一个 SqlSessionFactory
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
defaultSqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
cartSqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"shoppingcart");
reportSqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"reports");
创建 SqlSessionFactory 时,如果没有明确指定环境 environment id,则会使用默认的环境 environment 来创建。在上述的源码中,默认的 SqlSessionFactory 便是使用 shoppingcart 环境设置创建的。
对于每个环境 environment,我们需要配置 dataSource 和 transactionManager 元素
dataSource 配置
dataSource 元素被用来配置数据库连接属性。
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
dataSource 的类型可以配置成其内置类型之一,如 UNPOOLED、POOLED、JNDI。
如果将类型设置成 UNPOOLED,MyBatis 会为每一个数据库操作创建一个新的连接操作完成后关闭它。该方式适用于只有小规模数量并发用户的简单应用程序上。
如果将属性设置成 POOLED,MyBatis 会创建一个数据库连接池,连接池中的一个连接将会被用作数据库操作。一旦数据库操作完成,MyBatis 会将此连接返回给连接池。在开发或测试环境中,经常使用此种方式。
如果将类型设置成 JNDI,MyBatis 从在应用服务器向配置好的 JNDI 数据源 dataSource 获取数据库连接。在生产环境中,优先考虑这种方式。
transactionManager 配置
transactionManager 用来配置事务管理器,MyBatis 支持两种类型的事务管理器:JDBC 和 MANAGED。
JDBC 事务管理器被用作当应用陈旭负责管理数据库连接的生命周期(提交、回退等等)的时候。当 TransactionManager 属性设置成 JDBC,MyBatis 内部将使用 JdbcTransactionFactory 类创建 TransactionManager。
例如,部署到 Apache Tomcat 的应用程序,需要应用程序自己管理事务。
MANAGED 事务管理器是当由应用服务器负责管理数据库连接生命周期的时候使用。当你将 TransactionManager 属性设置成 MANAGED 时,MyBatis 内部使用 ManagedTransactionFactory 类创建事务管理器 TransactionManager。
例如,当一个 JavaEE 的应用程序部署在类似 JBoss、WebLogin、GlassFish 应用服务器上时,它们会使用 EJB 进行应用服务器的事务管理能力。在这些管理环境中,你可以使 MANAGED 事务管理器。
Managed 是托管的意思,即是应用本身不去管理事务,而是把事务管理交给应用所在的服务器进行管理。
properties 配置
properties 属性配置元素,可以将配置值具体化到一个属性文件中,并且使用属性文件的 key 名作为占位符。在上述的配置中,我们将数据库连接属性具体化到 application.properties 文件中,并且为 driver、url 等属性使用了占位符。
- 1、在 application.properties 文件中配置数据库连接参数,如下所示:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis3
jdbc.username=root
jdbc.password=root
- 2、在 mybatis-config.xml 文件中,使属性为 application.properties 文件中定义的占位符
<properties resource="application.properties">
<property name="jdbc.username" value="admin" />
<property name="jdbc.password" value="123456" />
</properties>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
可以在<properties>元素中配置默认参数的值。如果在<properties>中定义的元素和属性文件定义元素的 key 值相同,它们会被属性未鉴中定义的值覆盖。
<properties resource="application.properties">
<property name="jdbc.username" value="admin" />
<property name="jdbc.password" value="123456" />
</properties>
如果 application.properties 文件包含值 jdbc.username 和 jdbc.password,则上述定义的 username 和 password 的值 admin 和 123456 将会被 application.properties 中定义的对应的 jdbc.username 和 jdbc.password 值覆盖。
typeAliases 类型别名配置,在 SQLMapper 配置文件中,对于 resultType 和 parameterType 属性值,需要使用 JavaBean 的完全限定名:
<select id="findStudentById" parameterType="int" resultType="xx.mybatis3.domain.Student">
SELECT STUD_ID AS ID,NAME,EMAIL,DOB FROM STUDENTS WHERE STUD_ID=#{id}
</select>
<update id="updateStudent" parameterType="xx.mybatis3.domain.Student">
UPDATE STUDENTS SET NAME=#{name},EMAIL=#{email},DOB=#{dob} WHERE STUD_ID=#{id}
</update>
我们可以为完全限定名取一个别名(alias),然后其所需要使用完全限定名的地方使用别名,而不是导出使用完全限定名。
<typeAliases>
<typeAlias alias="Student" type="xx.mybatis3.domain.Student" />
<typeAlias alias="Teacher" type="xx.mybatis3.domain.Teacher" />
<package name="xx.mybatis3.domain" />
</typeAliases>
然后在 SQL Mapper 映射文件中,如下使用 Student 的别名:
<select id="findStudentById" parameterType="int" resultType="Student">
SELECT STUD_ID AS ID,NAME,EMAIL,DOB FROM STUDENTS WHERE STUD_ID = #{id}
</select>
不需要为每一个 JavaBean 单独定义别名,可以为提供需要取别名的 JavaBean 所在的包(package),MyBatis 会自动扫描包内定义的 JavaBeans,然后分别为 JavaBean 注册一个小写字幕开头的非完全限定的类名形式的别名。如下所示,提供一个需要为 JavaBeans 起别名的包名:
<typeAliases>
<package name="xx.mybatis3.domain" />
</typeAliases>
如果 Student.java 定义在 xx.mybatis3.domain 包中,则 xx.mybatis3.domain.Student 的别名会被注册为 student。
还有另外一种方式为 JavaBeans 起别名,使用注解 @Alias
@Alias("StudentAlias")
public class Student{
}
@Alias 注解将会覆盖配置文件中的<typeAliases>定义。
typeHandlers 配置
typeHandlers 用来配置类型处理器,当 MyBatis 将一个 Java 对象作为输入参数执行 INSERT 语句操作时,它会创建一个 PreparedStatement 对象,并且使用 setXXX()方式对占位符设置相应的参数值。这里 XXX 可以是 Integer、String、Date 等 Java 对象属性类型的任意一个。
当 MyBatis 是怎么知道对于 Integer类型属性使用 setInt() 和 String 类型属性使用 setString()方法呢?其实 MyBatis 是通过使用类型处理器(type handlers)来决定这么做的。
settings 配置
settings 配置用来设置全局参数,为满足应用特定的需求 MyBatis 默认的全局参数设置可以被 settings 设置覆盖掉。
<settings>
<setting name="cacheEnabled" value="true" />
<setting name="lazyLoadingEnabled" value="true" />
<setting name="multipleResultSetsEnabled" value="true" />
<setting name="useColumnLabel" value="true" />
<setting name="useGenerateKeys" value="false" />
<setting name="autoMappingBehavior" value="PARTIAL" />
<setting name="defaultExecutorType" value="SIMPLE" />
<setting name="defaultStatementTimeout" value="25000" />
<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>
mappers 配置
Mapper XML 文件中包含的 SQL 映射语句将会被应用通过使用其 statement id 来执行,需要在 mybatis-config.xml 文件中配置 SQL Mapper 文件的位置。
<mappers>
<mapper resource="xx/mybatis3/mappers/StudentMapper.xml" />
<mapper url="file:///E:/"xx/mappers/StudentMapper.xml" />
<mapper class="xx.mybatis3.mappers.StudentMapper" />
</mappers>
- resource 属性用来指定在 classpath 中的 mapper 文件
- url 属性用来通过完全文件系统路径或者 web URL 地址来指定 mapper 文件
- class 属性用来指向一个 mapper 接口
- package 属性用来指向可以找到 Mapper 接口的包名