配置文件层次结构
<?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><property name="" value=""/></properties>
<!-- 设置 -->
<settings><setting name="" value=""/></settings>
<!-- 定义别名 -->
<typeAliases/>
<!-- 类型处理器 -->
<typeHandlers/>
<!-- 对象工厂 -->
<objectFactory type=""/>
<!-- 插件 -->
<plugins><plugin interceptor=""></plugin></plugins>
<!-- 配置环境 -->
<environments default="">
<!-- 环境变量 -->
<environment id="">
<!-- 事务管理器 -->
<transactionManager type=""/>
<!-- 数据源 -->
<dataSource type="">
<property name="driver" value=""/>
<property name="url" value=""/>
<property name="username" value=""/>
<property name="password" value=""/>
</dataSource>
</environment>
</environments>
<!-- 数据库厂商标识 -->
<databaseIdProvider type=""/>
<!-- 映射器 -->
<mappers><mapper resource=""/></mappers>
</configuration>
这是全部的MyBatis的配置元素,这些层次是不能颠倒顺序的,否则会出现异常。
properties元素
可以配置属性,配置完可以在上下文中使用配置好的属性。类似Java中的成员变量。
property子元素
以数据库连接为例:
<!-- 属性 -->
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mysql"/>
<property name="username" value="root"/>
<property name="password" value="mysql"/>
</properties>
这样就可以在数据库连接时使用${driver}调用它的值了:
<!-- 数据源 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
properties配置文件
如果不喜欢硬编码,可以自己编写properties文件,在< properties />中引用即可:
<properties resource="dataSource.properties">
程序参数传递
在实际工作中,数据库名和密码是保密的,为了安全,需要加密所以我们的配置文件中往往配置的是加密过后的数据库信息,而无法通过加密的字符串去连接数据库,可以通过编码的形式来满足要求。
假设dataSource.properties中的username和password两个属性使用了加密的字符串,这个时候需要在生成SqlSessionFactory之前将它转换为明文,使用上一篇文章(java-加密字符串)方法加密后配置properties文件。使用相同的密匙解码后,再创建SqlSessionFactory。
- dataSource.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mysql
username=8ae22e349108d706
password=9fa4eecea7cac247
- SqlSessionFactoryUtil
private static SqlSessionFactory sqlSessionFactory=null;
private static final Class<SqlSessionFactoryUtil> CLASS_LOCK=SqlSessionFactoryUtil.class;
/**
* 私有化构造参数
*/
private SqlSessionFactoryUtil(){};
public static SqlSessionFactory initSqlSessionFactory(){
String xmlResource="mybatis-config.xml";
String jdbcProperty="jdbc.properties";
InputStream cfgStream=null;
Reader cfgReader=null;
InputStream proStream=null;
Reader proReader=null;
Properties p=null;
try {
//读入配置文件流
cfgStream=Resources.getResourceAsStream(xmlResource);
cfgReader=new InputStreamReader(cfgStream);
//读入属性文件
proStream=Resources.getResourceAsStream(jdbcProperty);
proReader=new InputStreamReader(proStream);
p=new Properties();
p.load(proReader);
//解密
String encUsername=p.getProperty("username");
String encPassword=p.getProperty("password");
DesUtils des;
try {
//注意使用同样的密匙
des = new DesUtils("tsd");
String decUsername=des.decrypt(encUsername);
String decPassword=des.decrypt(encPassword);
System.out.println(decUsername+decPassword);
p.setProperty("username", decUsername);
p.setProperty("password", decPassword);
} catch (Exception e) {
e.printStackTrace();
}
} catch (IOException e) {
Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SEVERE, null,e);
}
synchronized (CLASS_LOCK) {
if(sqlSessionFactory==null){
sqlSessionFactory=new SqlSessionFactoryBuilder().build(cfgReader,p);
}
}
return sqlSessionFactory;
}
public static SqlSession openSqlSession() {
if(sqlSessionFactory==null){
initSqlSessionFactory();
}
return sqlSessionFactory.openSession();
}
优先级
-
MyBatis支持的三种配置方式(property元素,resource属性和java代码)可能同时出现,它们的加载顺序是:
- 1.properties元素中指定的属性首先被读取;
- 2.resource属性指定的类路径或url属性指定的路径下的属性文件,并覆盖已读取的同名属性
- 3.读取作为方法参数传递的属性,并覆盖已读取的同名属性
- 因此,通过方法参数传递的属性具有最高优先级,resource/url属性中指定的配置文件次之,最低优先级是properties属性中指定的属性。
设置
设置(settings)在MyBatis中是最复杂的配置,同时也是最为重要的配置内容之一,它会改变MyBatis运行时的行为。即使不配置也可以正常工作,此处列出settings的部分结构,具体含义可参考链接文章。可以用logImpl=log4j测试下日志。
<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="defaultExecutorType" value="SIMPLE" />
<setting name="defaultStatementTimeout" value="25" />
<setting name="safeRowBoundsEnabled" value="false" />
<setting name="mapUnderscoreToCamelCase" value="false" />
<setting name="localCacheScope" value="SESSION" />
<setting name="jdbcTypeForNull" value="OTHER" />
<setting name="logImpl" value="LOG4J" />
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
</settings>
别名
别名是一个指代的名称,因为类全限定名过长,所以希望用一个简短的名称去指代它,而这个名称可以在MyBatis上下文中使用。别名在MyBatis中分为系统定义别名和自定义别名。注意,在MyBatis中别名是不分大小写的。一个typeAliases的实例是在解析配置文件时生成的,然后长期保存在Configuration对象中。
系统定义别名
基础类型,如int,包装为_int;
包装类型,如Long,包装为long;
主要通过代码实现,它有一个TypeAliasRegister类,定义语句是:
registerAlias("string",String.class);
自定义别名
两种方法:
- 典型方法
<typeAliases>
<typeAlias type="com.yan.po.Role" alias="role"/>
</typeAliases>
2. 按包扫描
<typeAliases>
<package name="com.yan.po"/>
</typeAliases>
@Alias("role")
public class Role {/*some code*/}
typeHandler类型处理器
typeHandler常用的配置为Java类型和JDBC类型,作用是将两种类型互相转化。
系统定义的typeHandler
源码位于org.apache.ibatis.type.TypeHandler,一般如LongTypeHandler均实现TypeHandler接口,并继承BaseTypeHandler类。
源码参见:LongTypeHandler;
setParameter实PreparedStatement对象设置参数,它允许我们自己填写变换规则。
setResult则分为ResultSet用列名或下标来获取结果数据,其中还包括了用CallableStatement(存储过程)获取结果及数据的方法。
自定义typeHandler
枚举类型typeHandler
略;
ObjectFactory
envirronments配置环境
概述
配置环境可以注册多个数据源(dataSource),每一个数据源分为两大部分:一个是数据库源的配置,另外一个是数据库事务(transactionManager)的配置。
<!-- 定义数据库信息,默认使用development数据库构建环境 -->
<environments default="development">
<environment id="development">
<!-- 可选参数为
JDBC-在独立编码中常常使用
MANAGED-采用容器方式管理事务,在JNDI数据源中使用
自定义-适用于特殊应用
-->
<transactionManager type="JDBC"/>
<!--
UNPOOLED-非连接池,使用MyBatis提供的org.apache.ibatis.datasource.unpooled.UnpooledDataSource实现
POOLED-连接池,使用MyBatis提供的org.apache.ibatis.datasource.pooled.PooledDataSource实现
JNDI-使用org.apache.ibatis.datasource.jndi.JndiDataSourceFactory实现
自定义
-->
<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>
数据库事务
一般交给Spring来控制,此处不管。
数据源
databaseIdProvider数据库厂商标识
一个系统使用不同的数据库的情况较少,因此此标签不常用。MyBatis提供了默认的数据库厂商,包含SQL Server、MySQL、DB2和Oracle,我们也可以自己定义。其实可以通过
使用系统默认规则
默认规则表示如下:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="MySQL" value="mysql"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle"/>
</databaseIdProvider>
vendor是卖主、供应商的意思,不可随意更改type的值。
可以在mapper映射文件中通过databaseId属性指定数据库厂商:
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" databaseId="mysql">
select
<include refid="Base_Column_List" />
from role
where id = #{id,jdbcType=INTEGER}
</select>
需要注意的是,一旦在mapper文件中指明数据库厂商如mysql,那么mybatis-config.xml中也必须指明mysql,否则出现异常:
Invalid bound statement (not found): com.yan.dao.RoleMapper.selectByPrimaryKey
显式添加数据库厂商后,就可以通过sqlSessionFactory.getConfiguration().getDatabaseId()方法来显示了,此时会显示mysql,当然你可以自定义它的名称。
不使用系统默认规则
引入映射器的方法
- 类
<mappers>
<mapper class="com.yan.dao.RoleMapper"/>
</mappers>
- 类路径
<mappers>
<mapper resource="com/yan/mapper/RoleMapper.xml"/>
</mappers>
- 包
<mappers>
<package name="com.yan.dao"></package>
</mappers>
- 文件路径(未成功!)
<mappers>
<mapper url="file:///java/com/yan/mapper/RoleMapper.xml"/>
</mappers>
注意
- 类和包的引入方式需要接口和xml文件在同一个包中;
- 文件路径方式没有测试成功,不明所以,使用绝对路径和相对路径都不行,希望得到高人指点。