[Mybatis] Mybatis配置信息浅析 MyBatis简介(二)

框架与中间件 框架与中间件 1779 人阅读 | 0 人回复

官方文档入门篇中有明确说明

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的。

SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。

而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

配置文件是Mybatis应用的核心之一(另一个核心为SQL映射)

所以配置文件的根元素为Configuration,以下为一个空的配置文件结构

<?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>



</configuration>

总览

Mybatis的配置模块主要分为9大类

image.png

每个模块都是configuration的子元素

比如,第一个示例中使用到的environments 和mappers

image.png

每个模块都有各自的职责以及配置方式,重点是要理解每一个模块具体做了什么,具体如何设置就可以及时的翻阅官方文档。

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}"/>

......

</dataSource>

使用properties时,需要注意的就是覆盖优先级

可以使用resource指定一个properties文件

并且还可以在properties中设置

如果重名了怎么办?

会优先使用resource中指定的值

Mybatis应用的核心为SqlSessionFactory,而SqlSessionFactory又是可以通过SqlSessionFactoryBuilder获得

这些配置信息都是为了创建SqlSessionFactory而准备的

另外SqlSessionFactoryBuilder的创建方法中也可以显式的明确的传递参数

image.png

简言之,这些配置信息数据最终是给SqlSessionFactoryBuilder用来创建SqlSessionFactory的

显然如果此处显式的传递进入properties对象,那么则使用properties中的

  • 在 properties 元素体内指定的属性首先被读取。
  • 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
  • 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。

所以对于优先级,从高到低依次为:参数传递,resource指定,property指定

除非特殊情况,否则,没有必要利用这个优先级特性,可以直接使用外部的properties文件进行配置即可,全部安置于一个文件中,便于维护。

环境配置environments

MyBatis 可以配置成适应多种环境,也就是说你可以配置N个环境,然后选择其一使用。

比如开发、测试和生产环境需要有不同的配置

尽管可以配置多个环境,但是每个 SqlSessionFactory 实例只能选择其一

<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>

<pre class="prettyprint"><strong>注意点:</strong></pre>

每个environment都有一个ID

environments中有一个default值<environments default="development">

从方法可以看得出来,环境信息也是可以从方法传递的,如果传入将会使用指定的环境

否则,将会使用默认的

image.png

在第一个示例程序中,如果使用带有环境变量的参数的build方法,传入存在的environment的id信息,一切都照往常一般

image.png

映射器mappers

去哪里找我们定义好的mapper文件?这就是映射器mappers的作用

有四种方式可以设置

第一个为基于类路径的一个相对路径,使用resource

第二个是物理路径,使用 url

第三个是对应接口的完全限定名,使用 class

第四个是将一个包下面所有的全部注册,使用 name

image.png

不管使用哪种方式形式都是下面的形式,指定符号为resource、url、class、name

<mappers>
<mapper 指定符号="指定符号对应格式的字符串"/>

......

</mappers>

settings

设置信息是Mybatis的核心调整参数,上面的数据库连接信息是属于必备的基础信息,而settings的配置项目则侧重于细节,行为的调整

一个很直观的例子就是音乐播放器的音效调整

image.png

如果不对这些项目进行设置,一般都有一个默认的值,可以认为是软件的推荐设置,音乐播放器也可以完全正常的进行工作,不会因为未设置而无法运行或者出现问题。

但是,如果进行设置,这些设置项目可能会对你的音质音效产生很大的影响。

Mybatis的settings选项中的各个参数就非常类似音乐播放器中音效的设置。

比如

cacheEnabled

表示:全局地开启或关闭配置文件中的所有映射器已经配置的任何缓存。

值为 true或者false ,默认值为true

对于所有的项目官方文档中均有明确的说明,使用时务必参照文档

别名 typeAliases

别名类似于数据库查询的别名,只是一个名字,仅此而已。

alias后面是别名,type是完全限定名

<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>

......

</typeAliases>

他只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余

可以使用上面的方式逐个指定

还可以指定一个包,这样的话包下面所有的类将会有自动的别名,会使用 Bean 的首字母小写的非限定类名来作为它的别名

比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。看下面的例子:

@Alias("author")publicclassAuthor{...}

如果一个具有一定规模的项目,多人开发每个人都指定别名,不知道这到底是好事还是坏事?

对于一些内建的类型也建立了相应的别名结构,可以参考官方文档

比如:

别名 映射的类型

_byte byte

类型处理 typeHandlers

类型处理器尽管平时总是用不到,但是却无时无刻不再被使用

无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。

因为Mybatis内置了默认的类型处理器,很多时候我们并不需要对他进行处理

在JDBC中对于一个字段我们需要setInt 或者getString这种形式的方法对字段进行处理,在Mybatis中,这些都是自动的

Mybatis之所以能够将字段与Java类型进行对应,依靠的就是typeHandler

简言之,可以认为是一个中间层方法

image.png

比如

IntegerTypeHandler,Java类型为java.lang.Integer, int,数据库兼容 NUMERIC 或 INTEGER

细节此处不介绍,简单说就是:当遇到Java Integer类型的数据时,就调用IntegerTypeHandler,这个类型处理器就相当于完成了setInt的工作

Mybatis内置了很多的类型处理器,所以通常我们并不需要做什么,Mybatis总是能够将类型与字段进行正确的映射

当需要更高级深层的处理时,可以考虑自定义typeHandler,他就是字段与Java类型之间的一个转接头

插件 plugins

插件通常在于以可插拔的形式动态的增加功能或者配置,Mybatis的插件则是侧重于在方法调用过程中,增加一些自定义的处理

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用,默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)

ParameterHandler (getParameterObject, setParameters)

ResultSetHandler (handleResultSets, handleOutputParameters)

StatementHandler (prepare, parameterize, batch, update, query)

可以这么理解,在Mybatis的整个处理过程中,有一些过程的调用中,允许用户插入自定义的执行逻辑

假设有一个对象a,调用了对象b的方法function,允许在b方法调用前添加一定的逻辑

这含义是不是非常的类似代理呢?调用真实对象之前添加方法?

事实上插件的逻辑就是代理。

简言之,可以认为插件就是在某些方法调用时植入逻辑。

数据库厂商标识符 databaseIdProvider

一个项目,可能配置了不同的数据库映射文件,比如一个项目可以使用MYSQL或者ORACLE

对于不同的数据库,部分SQL可能会有所不同,这很正常,如何灵活的配置这两套SQL执行方案?

在Mybatis中使用的是数据库厂商标识符

每个数据库都有一个名称字符串,可以通过方法进行获取,假设MYSQL 返回的字符串标识符为 mysql

现在我知道了目标数据库的名称,我如果知道哪些SQL是这个数据库的不就好了么

那么,如何标记每个SQL都是属于哪个数据库的呢?

如下图所示,每一个SQL中,有一个databaseId属性可以设置,通过他可以配置这个SQL映射属于哪个数据库

image.png

本文作者:程序员潇然 疯狂的字节X https://crazybytex.com/

有了数据库的标识符,再有了每个SQL的标识符,自然就可以完成匹配了

比如上面的SQL databaseId的值为“mysql”,当遇到数据库的名称标识符为“mysql”时,仅仅加载databaseId的值为“mysql”的映射即可。

但是还有一个问题:

由于通常情况下这个数据库名称的标识符字符串都非常长而且相同产品的不同版本会返回不同的值

所以最好通过设置属性别名来使其变短,而且通过别名做中转,当更换版本时,项目中不需要变更

所以数据库厂商标识符的完整的用法就是借助于databaseIdProvider模块

第一步配置需要的数据库名称信息

value的值为别名,name的值为所需要匹配的字符串

也就是说如果获取到的数据库名称标识符中包含name中设置的值,那么当前的databaseId就是value的值

总之,value的值才是项目中使用的,name的值是需要进行匹配的

匹配键,使用值

<databaseIdProvider type="DB_VENDOR">
  <property name="SQL Server" value="sqlserver"/>
  <property name="DB2" value="db2"/>
  <property name="Oracle" value="oracle" />
</databaseIdProvider>

<pre class="prettyprint"><strong>第二步就是配置每个SQL映射的databaseId属性值</strong></pre>

最终,如果配置了 databaseIdProvider,MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库 databaseId 属性的所有语句。

如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。

对象工厂 objectFactory

MyBatis是我们仅仅专注于SQL的编写,完成了字段到Java类型对象的转换

既然是ORM框架,从关系型数据库中检索到的信息终归是要创建对象的

在Mybatis中,使用一个对象创建工厂ObjectFactory的实例来完成

默认的对象工厂需要做的仅仅是实例化目标类,要么通过默认构造方法,要么在参数映射存在的时候通过参数构造方法来实例化。一个无参一个有参

对应代码的话就是其中的两个create方法,一个是处理默认构造方法的,另外一个是处理带参数的构造方法的

image.png

想要实现自己的对象创建工厂,可以通过继承 DefaultObjectFactory

image.png

继承了DefaultObjectFactory之后,将自己的ObjectFactory配置即可

如下图所示

image.png

总结

以上为Mybatis配置文件中各个模块的简单介绍,重在介绍模块的功能,具体用法还需要参考官方文档

从配置文件也可以看得出来,Mybatis的配置条理清晰,各个模块各司其职,而且非常的灵活

  • 通过properties可以对元素进行设置
  • 通过environments对环境进行指定
  • 通过mappers对映射文件进行定位
  • 通过settings设置可以对Mybatis进行高级调优
  • 通过typeAliases别名可以简化名称,简捷使用
  • 通过typeHandlers类型处理可以对数据与Java类型的转换进行高级设置
  • 通过plugins插件可以在Mybatis执行逻辑中植入逻辑功能
  • 通过databaseIdProvider数据库厂商标识符 可以灵活应用部署多数据库
  • 通过objectFactory对象工厂可以个性化对象的创建

以上各个模块都是configuration的子元素,放置于configuration内

需要注意的是各个元素之间也是有顺序的,有顺序的,在DTD文件中可以看到

image.png

如果顺序不当是会报错的

image.png

common_log.png 转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-165-1-1.html

关注下面的标签,发现更多相似文章
    黄小斜学Java

    疯狂的字节X

  • 目前专注于分享Java领域干货,公众号同步更新。原创以及收集整理,把最好的留下。
    包括但不限于JVM、计算机科学、算法、数据库、分布式、Spring全家桶、微服务、高并发、Docker容器、ELK、大数据等相关知识,一起进步,一起成长。
热门推荐
[若依]微服务springcloud版新建增添加一个
[md]若依框架是一个比较出名的后台管理系统,有多个不同版本。
[CXX1300] CMake '3.18.1' was not
[md][CXX1300] CMake '3.18.1' was not found in SDK, PATH, or
海康摄像头接入 wvp-GB28181-pro平台测试验
[md]### 简介 开箱即用的28181协议视频平台 `https://github.c