【Mybatis从0到1-007】深入MyBatis的配置文件

   根据前面学过的内容,可知,mybatis的持久化离不开sqlsessionfactory对象,这个对象是整个数据库映射关系经过编译后的内存镜像,该对象的openSession()方法可以打开SqlSession对象。该对象由SqlSessionFactoryBuilder加载mybatis的配置文件产生。再来回顾下之前的代码:

// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过工厂得到SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
   上面这段代码的功能是根据配置文件SqlMapConfig.xml,创建SqlSessionFactory 对象,然后产生SqlSession对象,执行SQL语句。而mybatis的初始化就发生在第三句:

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
现在,来看下,这句代码到底发生了什么?

MyBatis初始化的基本过程:

   SqlSessionFactoryBuilder根据传入的数据流生成Configuration对象,然后根据Configuration对象创建默认的SqlSessionFactory实例。

   初始化的基本过程如下所示:

【Mybatis从0到1-007】深入MyBatis的配置文件

简述初始化的过程:

1.调用SqlSessionFactoryBuilder对象的build(inputStream)方法;

2.SqlSessionFactoryBuilder会根据输入流inputStream等信息创建XMLConfiguration对象;

3.SqlSessionFactoryBuilder调用XMLConfiguration对象的parse()方法;

4.XMLConfiguration对象解析XML配置文件并返回Configuration对象;

5.SqlSessionFactoryBuilder根据Configuration对象创建一个DefaultSessionFactory对象;

6.SqlSessionFactoryBuilder返回DefaultSessionFactory对象给客户端,供客户端使用。

由此可见,SqlSessionFactory是根据mybatis的配置文件创建的。下面开始简单介绍全局配置文件SQLMapConfig.xml

配置内容如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)

【1】properties(属性

由xml文件内容可以发现,文件中存在很多硬编码,现在我们的需求如下:

将数据库连接参数单独配置在db.properties中(原因:方便对参数进行统一管理,其它xml可以引用该db.properties),只需要在SqlMapConfig.xml中加载db.properties的属性值。在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。

下面,开始修改全局配置文件,创建文件db.properties(路径:src\main\resources\db.properties),添加内容如下:

jdbc.driver =com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username = root
jdbc.password = 123

修改SqlMapConfig.xml文件,如下:

【Mybatis从0到1-007】深入MyBatis的配置文件

修改完成后,可以将上一章【Mybatis从0到1-006】mybatis开发DAO之基于mapper代理的测试程序再次运行下,看是否还能正常运行,测试结果表明,配置正确。

总结:

MyBatis 将按照下面的顺序来加载属性:
在 properties 元素体内定义的属性首先被读取。 
然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。 
最后读取parameterType传递的属性,它会覆盖已读取的同名属性。所以这里可能就会存在一个问题:假如UserMapper.xml中的有一个statement的入参名为name,

<select id="findUserByUsername" parameterType="java.lang.String" resultType="po.User">
    SELECT *FROM  user WHERE username LIKE '%${name}%'
</select>
而db.properties中也有一个参数名叫name。

name = root
jdbc.password = 123

那最终UserMapper.xml中的select会读取到name=root,而不是用户传入的值。

建议:
不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX

【2】typeAliases(别名)

   在mapper.xml中,定义了很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。
   如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。

   mybatis有一些默认的别名,这里不再罗列,主要说一下自定义别名。类型别名是为了java类型设置的一些短的名字,它只和xml配置有关,存在的意义仅在于用来减少类完全限定名的冗余。

<typeAliases>
    <!--创建单个别名-->
    <typeAlias type="po.User" alias="user"></typeAlias>
</typeAliases>

这样配置时,user可以使用在任何使用po.User的地方。

<select id ="findUserById" parameterType="int" resultType="user">
    SELECT *FROM user WHERE id=#{id}
</select>

除此外,还可以批量定义别名(常用), 指定一个包名,mybatis会在包下面扫描需要的java bean。

<typeAliases>
    <!--创建单个别名-->
    <!--<typeAlias type="po.User" alias="usersong"></typeAlias>-->
    <!--批量别名-->
    <package name="po"/>
</typeAliases>
每一个在包po中的java bean,在没有注解的情况下,会使用Bean的首字母小写的非限定类名来作为它的别名。比如po.User的别名为user;若有注解的话,则它的别名为其注解值。

@Alias("user")
public class User {
	…………
}

【3】mapper映射器

   mybatis需要开发者自己书写SQL语句,mapper映射器正是告诉MyBatis到哪里去找映射文件(在SqlMapConfig.xml文件中修改),进而找到这些SQL语句。实际开发中,可以使用相对于类路径的资源引用或完全限定资源定位符(包括file:///的URL),以及类名和包名等。例如:

3.1 通过resource加载单个映射文件(我们之前开发的都是基于此加载方式)

<!-- 加载 映射文件 -->
<mappers>
    <!--<mapper resource="sqlmap/User.xml"/>-->
    <mapper resource="mapper/UserMapper.xml"/>
</mappers>

3.2 通过本地文件

<mappers>
    <mapper url="file:///C:/mapper/UserMapper.xml"/>
</mappers>

3.3 通过mapper接口加载单个映射文件(使用这种方法的前提是:使用的是mapper代理方法

这种方法开发还需要遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在同一个目录中!!!

<!-- 加载 映射文件 -->
<mappers>
    <!--<mapper resource="sqlmap/User.xml"/>-->
    <!--通过resource加载单个映射文件-->
    <!--<mapper resource="mapper/UserMapper.xml"/>-->
    <!--加载本地文件-->
    <!--<mapper url="file:///C:/mapper/UserMapper.xml"/>-->
    <!-- 通过mapper接口加载单个 映射文件
    遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中
    上边规范的前提是:使用的是mapper代理方法 -->
    <mapper class="mapper.UserMapper"/>
</mappers>

 通过idea开发,在测试mapper接口过程中,出现了一个问题,就是当把resources\mapper文件夹下的UserMapper.xml文件移动到src\main\java\mapper后,两个文件虽在同一目录了,但是运行测试程序,报错。

【Mybatis从0到1-007】深入MyBatis的配置文件

出现这个问题的原因是idea中我将mapper类型默认是source类型,而xml文件在发布时不会编译,同时也不会发布到target中(所以在发布之后target目录中并没有xml,路径:target\classes\mapper\),导致项目运行时找不到mapper.xml文件。

然而,当只遵循部分规范(需要将mapper接口类名和mapper.xml映射文件名称保持一致),不遵循且在同一个目录中!!!,运行程序,居然没有报错,真的很奇怪!!

…………………………………………………………………………………………………………………………………………………………………………………………………………………………………………

对于这个问题,网友解释如下:

解决方案:

    将UserMapper.xml文件提取到指定文件夹mapper中,设置mapper文件夹类型为resources,在SqlMapConfig.xml配置文件中添加图片中框选的代码对mapper文件进行扫描,问题解决。【这个问题在学习完Spring与mybatis结合之后将更容易解决。】

【Mybatis从0到1-007】深入MyBatis的配置文件

3.4 批量加载mapper(推荐使用)

批量加载与3.3所说的加载单个映射文件原理相似,只不过是一个用了class,一个用了package,这里先贴出代码。

<!-- 批量加载mapper
指定mapper接口的包名,mybatis自动扫描包下边所有mapper接口进行加载
遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录 中
上边规范的前提是:使用的是mapper代理方法
 -->
<package name="mapper"/>

以上就是mybatis的配置文件的最主要内容。接下来章节将介绍输入映射、输出映射。