共计 36205 个字符,预计需要花费 91 分钟才能阅读完成。
封面:洛小汐
作者:潘潘
做小事和做小事的难度是一样的。两者都会耗费你的工夫和精力,所以如果信心做事,就要做小事,要确保你的幻想值得谋求,将来的播种能够配得上你的致力。
前言
上一篇文章 《Mybatis 系列全解(三):Mybatis 简略 CRUD 应用介绍》,咱们基本上手了 Mybatis 的增删改查操作,也感触到 Mybatis 的简略高效舒美,然而必定有局部敌人对于 Mybatis 的配置文件只是理解根本组成和大抵用法,尚无一套残缺的构造记忆,所以本篇文章咱们将具体的介绍 Mybatis 的配置全貌,毕竟 Mybatis 的配置文件对于整个 Mybatis 体系的构建与撑持有着深远的影响。
Mybatis 系列全解脑图分享,继续更新中
Mybaits 系列全解 (继续更新)
- Mybatis 系列全解(一):手写一套长久层框架
- Mybatis 系列全解(二):Mybatis 简介与环境搭建
- Mybatis 系列全解(三):Mybatis 简略 CRUD 应用介绍
- Mybatis 系列全解(四):全网最全!Mybatis 配置文件 XML 全貌详解
- Mybatis 系列全解(五):全网最全!详解 Mybatis 的 Mapper 映射文件
- Mybatis 系列全解(六):Mybatis 最硬核的 API 你晓得几个?
- Mybatis 系列全解(七):全息视角看 Dao 层两种实现形式之传统形式与代理形式
- Mybatis 系列全解(八):Mybatis 的动静 SQL
- Mybatis 系列全解(九):Mybatis 的简单映射
- Mybatis 系列全解(十):Mybatis 注解开发
- Mybatis 系列全解(十一):Mybatis 缓存全解
- Mybatis 系列全解(十二):Mybatis 插件开发
- Mybatis 系列全解(十三):Mybatis 代码生成器
- Mybatis 系列全解(十四):Spring 集成 Mybatis
- Mybatis 系列全解(十五):SpringBoot 集成 Mybatis
- Mybatis 系列全解(十六):Mybatis 源码分析
目录
1、为什么要应用配置文件
2、Mybatis 配置全貌
3、XML 外围配置
4、XML 映射文件
5、总结
为什么要应用配置文件
试想,如果没有配置文件,咱们的应用程序将只能沿着固定的姿势运行,简直不能做任何动静的调整,那么这不是一套完满的设计,因为咱们心愿领有更宽更灵便的操作空间和更多的兼容度,同时也能解决硬编码等问题,所以咱们须要有配置文件,对应用程序进行参数预设和设置初始化工作。
那咱们为何钟情 XML?
首先,当然是 XML 配置文件自身就足够优良,格局标准,存储小,跨平台,读取快 … 等等,所谓窈窕淑女,谁人不爱。
其次,也是一个重要影响因素,就是各大畛域大佬的反对,像微软、像 Java 系 … 等等,世上本无路,只是走的人多了,也就成了路(这句话是鲁迅老先生说的)。
所以,Mybatis 抉择搭配 XML 配置,实属正当。
Mybatis 配置全貌
Mybatis 框架自身,实践上就一个配置文件,其实也只须要一个配置文件,即 mybatis-config.xml(当然文件名容许自在命名),只不过这个配置文件其中的一个属性 mappers(映射器),因为可能产生过多的 SQL 映射文件,于是咱们物理上独自拓展进去,容许使用者定义任意数量的 xxxMapper.xml 映射文件。
把 SQL 映射文件独自配置,是有益处的,一是灵便度上容许任意拓展,二也防止了其它无需常常变动的属性配置遭逢误改。
咱们看看 Mybatis 官网给出的配置文件层次结构:
-
configuration(配置)
- properties(属性)
- settings(设置)
-
typeAliases(类型别名)
- 三种别名定义形式
-
typeHandlers(类型处理器)
- 自定义类型处理器
- objectFactory(对象工厂)
- plugins(插件)
-
environments(环境配置)
-
environment(环境变量)
- transactionManager(事务管理器)
-
dataSource(数据源)
- 三种反对数据源与自定义数据源
-
- databaseIdProvider(数据库厂商标识)
- mappers(映射器)
理论配置文件 XML 内容如下,除了束缚头 <?xml> 与 <!DOCTYPE>,
其余标签元素都是 Mybatis 的外围配置属性:
<?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>
<!-- 1、属性:例如 jdbc.properties -->
<properties resource="jdbc.properties"></properties>
<!-- 2、设置:定义全局性设置,例如开启二级缓存 -->
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 3、类型名称:为一些类定义别名 -->
<typeAliases>
<typeAlias type="com.panshenlian.pojo.User" alias="user"></typeAlias>
</typeAliases>
<!-- 4、类型处理器:定义 Java 类型与数据库中的数据类型之间的转换关系 -->
<typeHandlers></typeHandlers>
<!-- 5、对象工厂 -->
<objectFactory type=""></objectFactory>
<!-- 6、插件:mybatis 的插件,反对自定义插件 -->
<plugins>
<plugin interceptor=""></plugin>
</plugins>
<!-- 7、环境:配置 mybatis 的环境 -->
<environments default="development">
<!-- 环境变量:反对多套环境变量,例如开发环境、生产环境 -->
<environment id="development">
<!-- 事务管理器:默认 JDBC -->
<transactionManager type="JDBC" />
<!-- 数据源:应用连接池,并加载 mysql 驱动连贯数据库 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<!-- 8、数据库厂商标识 -->
<databaseIdProvider type=""></databaseIdProvider>
<!-- 9、映射器:指定映射文件或者映射类 -->
<mappers>
<mapper resource="UserMapper.xml" />
</mappers>
</configuration>
必须留神:Mybatis 配置文件的属性地位程序是 固定 的,不容许 颠倒程序,否则 Mybatis 在解析 XML 文件的时候就会抛出异样,这个与 Mybatis 框架启动加载配置信息程序无关,后续咱们源码剖析会讲到。
以上根本可能清晰看明确 Mybatis 配置文件的层次结构关系,咱们简略画一张脑图:
根本是须要咱们把握 9 大顶级元素配置,其中标记 橘红色 的属性配置,因为波及 插件 和 动静 SQL,插件配置能够利用于分页与性能加强等,动静 SQL 例如 if 标签、where 标签、foreach 标签等,初步了解为利用于 SQL 语句拼接。这两块属于 Mybatis 的两个个性,咱们后续独自具体进行梳理探讨。
XML 外围配置
咱们的外围配置文件 configuration(配置)作为最顶级节点,其余 9 大属性都必须嵌套在其内,对于外部 9 大节点,咱们逐个解说:
1、properties(属性)
属性标签,不言而喻就是提供属性配置,可进行动静替换,个别能够在 Java 属性文件中配置,例如 jdbc.properties 配置文件,或通过 properties 元素标签中的子元素 property 来指定配置。
举例咱们须要配置数据源信息,采纳 property 标签能够这样配置:
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/myDB"/>
<property name="username" value="user1"/>
<property name="password" value="123456"/>
</properties>
设置好的属性能够在整个配置文件中用来替换须要动静配置的属性值。比方:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
或者咱们应用 Java 中的属性配置文件,把属性配置元素具体化到一个属性文件中,并且应用属性文件的 key 名作为占位符。例如 jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc\:mysql\://127.0.0.1\:3306/myDB
username=root
password=123456
应用时咱们把属性文件引入,并应用文件中定义的占位符,例如 db.driver:
<!-- 引入属性配置文件 -->
<properties resource="jdbc.properties"></properties>
<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 配置文件,同时又设置了 property 元素值,Mybatis 会应用哪边配置的属性值呢?例如这种状况:
<properties resource="jdbc.properties">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/myDB"/>
<property name="username" value="user1"/>
<property name="password" value="123456"/>
</properties>
这里,如果在 property 标签元素与 jdbc.properties 文件中同时存在雷同属性,那么属性文件将会笼罩 property 标签元素的属性,例如最终 username 属性值会应用 jdbc.properties 文件中设置的 root,而不会应用属性元素设置的 user1。这样理论为配置提供了诸多灵便抉择。
另外,properties 元素容许配置 resource 属性或 url 属性,只能二选一,要么应用 resource 指定本地的配置文件,要么应用 url 指定近程的配置文件,因为 Mybatis 在加载配置时,如果发现 url 与 resource 同时存在,会抛出异样禁止。
<!-- 配置 resource-->
<properties resource="xxx.properties">
<property name="driver" value="com.mysql.jdbc.Driver"/>
</properties>
<!-- 配置 url-->
<properties url="http://xxxx">
<property name="driver" value="com.mysql.jdbc.Driver"/>
</properties>
还有一种状况,像 Mybatis 在解析配置的时候,也能够在 Java 代码中构建属性 java.util.Properties 属性对象并传递到 SqlSessionFactoryBuilder.build() 办法中,例如:
// 构建属性对象
Properties props = new Properties();
props.setProperty("driver","com.mysql.jdbc.Driver");
props.setProperty("url","jdbc:mysql://127.0.0.1:3306/myDB");
props.setProperty("username","user1");
props.setProperty("password","123456");
// 传递属性构建 SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, props);
那么这三种形式都容许配置,那在属性配置反复的状况下,优先级别是怎么呢?
properties 优先级
1、第一优先级:在 Java 代码中构建的 properties 属性对象;
2、第二优先级:通过属性 resource 或 url 读取到的本地文件或近程文件;
3、第三优先级:间接在 properties 外部子标签元素 property 中设置的属性。
留神,在理论开发中,为了防止给前期保护造成困扰,倡议应用单一种配置形式。
2、settings(设置)
settings 标签元素,是 MyBatis 中极为重要的调整设置,它们会动静扭转 MyBatis 的运行时行为,这些配置就像 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="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<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"/>
<... more .../>
</settings>
-
属性 cacheEnabled
- 全局性地开启或敞开所有映射器配置文件中已配置的任何缓存
- 反对 true | false
- 默认 true
-
属性 lazyLoadingEnabled
- 提早加载的全局开关。当开启时,所有关联对象都会提早加载。特定关联关系中可通过设置 fetchType 属性来笼罩该项的开关状态。
- 反对 true | false
- 默认 false
-
属性 aggressiveLazyLoading
- 开启时,任一办法的调用都会加载该对象的所有提早加载属性。否则,每个提早加载属性会按需加载(参考 lazyLoadTriggerMethods)。
- 反对 true | false
- 默认 false(在 3.4.1 及之前的版本中默认为 true)
-
属性 multipleResultSetsEnabled
- 是否容许单个语句返回多后果集(须要数据库驱动反对)。
- 反对 true | false
- 默认 true
-
属性 useColumnLabel
- 应用列标签代替列名。理论体现依赖于数据库驱动,具体可参考数据库驱动的相干文档,或通过比照测试来察看。
- 反对 true | false
- 默认 true
-
属性 useGeneratedKeys
- 容许 JDBC 反对主动生成主键,须要数据库驱动反对。如果设置为 true,将强制应用主动生成主键。只管一些数据库驱动不反对此个性,但仍可失常工作(如 Derby)。
- 反对 true | false
- 默认 false
-
属性 autoMappingBehavior
- 指定 MyBatis 应如何主动映射列到字段或属性。NONE 示意敞开主动映射;PARTIAL 只会主动映射没有定义嵌套后果映射的字段。FULL 会主动映射任何简单的后果集(无论是否嵌套)。
- 反对 NONE, PARTIAL, FULL
- 默认 PARTIAL
-
属性 autoMappingUnknownColumnBehavior
-
指定发现主动映射指标未知列(或未知属性类型)的行为。
- NONE: 不做任何反馈
- WARNING: 输入正告日志(org.apache.ibatis.session.AutoMappingUnknownColumnBehavior 的日志等级必须设置为 WARN)
- FAILING: 映射失败 (抛出 SqlSessionException)
- 反对 NONE, WARNING, FAILING
- 默认 NONE
-
-
属性 defaultExecutorType
- 配置默认的执行器。SIMPLE 就是一般的执行器;REUSE 执行器会重用预处理语句(PreparedStatement);BATCH 执行器不仅重用语句还会执行批量更新。
- 反对 SIMPLE REUSE BATCH
- 默认 SIMPLE
-
属性 defaultStatementTimeout
- 设置超时工夫,它决定数据库驱动期待数据库响应的秒数。
- 反对 任意正整数
- 默认 未设置 (null)
-
属性 defaultFetchSize
- 动的后果集获取数量(fetchSize)设置一个倡议值。此参数只能够在查问设置中被笼罩。
- 反对 任意正整数
- 默认 未设置 (null)
-
属性 defaultResultSetType
- 指定语句默认的滚动策略。(新增于 3.5.2)
- 反对 FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置)
- 默认 未设置 (null)
-
属性 safeRowBoundsEnabled
- 是否容许在嵌套语句中应用分页(RowBounds)。如果容许应用则设置为 false。
- 反对 true | false
- 默认 false
-
属性 safeResultHandlerEnabled
- 是否容许在嵌套语句中应用后果处理器(ResultHandler)。如果容许应用则设置为 false。
- 反对 true | false
- 默认 true
-
属性 mapUnderscoreToCamelCase
- 是否开启驼峰命名主动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。
- 反对 true | false
- 默认 false
-
属性 localCacheScope
- MyBatis 利用本地缓存机制(Local Cache)避免循环援用和减速反复的嵌套查问。默认值为 SESSION,会缓存一个会话中执行的所有查问。若设置值为 STATEMENT,本地缓存将仅用于执行语句,对雷同 SqlSession 的不同查问将不会进行缓存。
- 反对 SESSION | STATEMENT
- 默认 SESSION
-
属性 jdbcTypeForNull
- 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。某些数据库驱动须要指定列的 JDBC 类型,少数状况间接用个别类型即可,比方 NULL、VARCHAR 或 OTHER。
- JdbcType 常量,罕用值:NULL、VARCHAR 或 OTHER。
- 默认 OTHER
-
属性 lazyLoadTriggerMethods
- 指定对象的哪些办法触发一次提早加载。
- 反对 用逗号分隔的办法列表。
- 默认 equals,clone,hashCode,toString
-
属性 defaultScriptingLanguage
- 指定动静 SQL 生成应用的默认脚本语言。
- 反对 一个类型别名或全限定类名。
- 默认 org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
-
属性 defaultEnumTypeHandler
- 指定 Enum 应用的默认 TypeHandler。(新增于 3.4.5)
- 反对 一个类型别名或全限定类名。
- 默认 org.apache.ibatis.type.EnumTypeHandler
-
属性 callSettersOnNulls
- 指定当后果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)办法,这在依赖于 Map.keySet() 或 null 值进行初始化时比拟有用。留神根本类型(int、boolean 等)是不能设置成 null 的。
- 反对 true | false
- 默认 false
-
属性 returnInstanceForEmptyRow
- 当返回行的所有列都是空时,MyBatis 默认返回 null。当开启这个设置时,MyBatis 会返回一个空实例。请留神,它也实用于嵌套的后果集(如汇合或关联)。(新增于 3.4.2)
- 反对 true | false
- 默认 false
-
属性 logPrefix
- 指定 MyBatis 减少到日志名称的前缀。
- 反对 任何字符串
- 默认 未设置
-
属性 logImpl
- 指定 MyBatis 所用日志的具体实现,未指定时将主动查找。
- 反对 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING
- 默认 未设置
-
属性 proxyFactory
- 指定 Mybatis 创立可提早加载对象所用到的代理工具。
- 反对 CGLIB | JAVASSIST
- 默认 JAVASSIST(MyBatis 3.3 以上)
-
属性 vfsImpl
- 指定 VFS 的实现
- 反对 自定义 VFS 的实现的类全限定名,以逗号分隔。
- 默认 未设置
-
属性 useActualParamName
- 容许应用办法签名中的名称作为语句参数名称。为了应用该个性,你的我的项目必须采纳 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1)
- 反对 true | false
- 默认 true
-
属性 configurationFactory
- 指定一个提供 Configuration 实例的类。这个被返回的 Configuration 实例用来加载被反序列化对象的提早加载属性值。这个类必须蕴含一个签名为 static Configuration getConfiguration() 的办法。(新增于 3.2.3)
- 反对 一个类型别名或齐全限定类名。
- 默认 未设置
-
属性 shrinkWhitespacesInSql
- 从 SQL 中删除多余的空格字符。请留神,这也会影响 SQL 中的文字字符串。(新增于 3.5.5)
- 反对 true | false
- 默认 false
-
属性 defaultSqlProviderType
- 指定一个自身拥查询方法的类(从 3.5.6 开始),这个类能够配置在注解 @SelectProvider 的 type 属性值上。
- 反对 一个类型别名或齐全限定类名。
- 默认 未设置
settings 反对了特地多功能反对,其实惯例开发中应用到的属性项不会特地多,除非我的项目有特殊要求,所以倡议大家把这些设置当做字典即可,不用详记 每一个属性应用,须要时翻阅研读。
3、typeAliases(类型别名)
类型别名能够给 Java 类型设置一个简称。它仅用于 XML 配置,意在升高冗余的全限定类名书写,因为书写类的全限定名太长了,咱们心愿有一个简称来指代它。类型别名在 Mybatis 中分为 零碎内置 和 用户自定义 两类,Mybatis 会在解析配置文件时把 typeAliases 实例存储进入 Configuration 对象中,须要应用时间接获取。
个别咱们能够自定义别名,例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
</typeAliases>
像这样配置时,咱们就能够在任何须要应用 domain.blog.Author 的中央,间接应用别名 author。
然而,如果遇到我的项目中特地多 Java 类须要配置别名,怎么更快的设置呢?
能够指定一个包名进行扫描,MyBatis 会在包名上面扫描须要的 Java Bean,比方:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
每一个在包 domain.blog 中的 Java Bean,在没有注解的状况下,会应用 Bean 的首字母小写的非限定类名来作为它的别名。比方 domain.blog.Author 的别名为 author;若有 注解,则别名为其自定义的注解值。见上面的例子:
@Alias("myAuthor")
public class Author {...}
Mybatis 曾经为许多常见的 Java 类型内建了相应的类型别名。上面就是一些为常见的 Java 类型内建的类型别名。它们都是不辨别大小写的,留神,为了应答原始类型的命名反复,采取了非凡的命名格调,能够发现 根本类型 的别名前缀都有下划线 ‘_’,而根本类型的 包装类 则没有,这个须要留神:
- 别名 _byte,对应的类型是:byte
- 别名 _long,对应的类型是:long
- 别名 _short,对应的类型是:short
- 别名 _int,对应的类型是:int
- 别名 _integer,对应的类型是:int
- 别名 _double,对应的类型是:double
- 别名 _float,对应的类型是:float
- 别名 _boolean,对应的类型是:boolean
- 别名 string,对应的类型是:String
- 别名 byte,对应的类型是:Byte
- 别名 long,对应的类型是:Long
- 别名 short,对应的类型是:Short
- 别名 int,对应的类型是:Integer
- 别名 integer,对应的类型是:Integer
- 别名 double,对应的类型是:Double
- 别名 float,对应的类型是:Float
- 别名 boolean,对应的类型是:Boolean
- 别名 date,对应的类型是:Date
- 别名 decimal,对应的类型是:BigDecimal
- 别名 bigdecimal,对应的类型是:BigDecimal
- 别名 object,对应的类型是:Object
- 别名 map,对应的类型是:Map
- 别名 hashmap,对应的类型是:HashMap
- 别名 list,对应的类型是:List
- 别名 arraylist,对应的类型是:ArrayList
- 别名 collection,对应的类型是:Collection
- 别名 iterator,对应的类型是:Iterator
咱们能够通过源码查看内置的类型别名的注册信息。
具体源码门路在 org.apache.ibatis.type.TypeAliasRegistry # TypeAliasRegistry():
public TypeAliasRegistry() {registerAlias("string", String.class);
registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);
registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);
registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);
registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);
registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);
registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);
registerAlias("ResultSet", ResultSet.class);
}
别名是不辨别大小写的,同时也反对数组类型,只须要加“[]”即可应用,比方 Long 数组别名咱们能够用 long[] 间接代替,例如在理论开发中,int、INT、integer、INTEGER 都是代表 Integer,这里次要因为 MyBatis 在注册别名的时候会全副转为小写字母进行存储,另外以上列表 无需牢记,仅仅在须要应用的时候查阅即可,根本也都能够看得明确。
4、typeHandlers(类型处理器)
MyBatis 在设置预处理 SQL 语句(PreparedStatement)中所须要的 参数 或从 后果集 ResultSet 中获取对象时,都会用类型处理器将获取到的值以适合的形式转换成 Java 类型。
类型处理器,次要用于解决 Java 类型与 JDBC 类型的映射匹配关系解决,下表形容了一些默认的类型处理器。
-
类型处理器 BooleanTypeHandler
- Java 类型:java.lang.Boolean, boolean
- JDBC 类型:数据库兼容的 BOOLEAN
-
类型处理器 ByteTypeHandler
- Java 类型:java.lang.Byte, byte
- JDBC 类型:数据库兼容的 NUMERIC 或 BYTE
-
类型处理器 ShortTypeHandler
- Java 类型:java.lang.Short, short
- JDBC 类型:数据库兼容的 NUMERIC 或 SMALLINT
-
类型处理器 IntegerTypeHandler
- Java 类型:java.lang.Integer, int
- JDBC 类型:数据库兼容的 NUMERIC 或 INTEGER
-
类型处理器 LongTypeHandler
- Java 类型:java.lang.Long, long
- JDBC 类型:数据库兼容的 NUMERIC 或 BIGINT
-
类型处理器 FloatTypeHandler
- Java 类型:java.lang.Float, float
- JDBC 类型:数据库兼容的 NUMERIC 或 FLOAT
-
类型处理器 DoubleTypeHandler
- Java 类型:java.lang.Double, double
- JDBC 类型:数据库兼容的 NUMERIC 或 DOUBLE
-
类型处理器 BigDecimalTypeHandler
- Java 类型:java.math.BigDecimal
- JDBC 类型:数据库兼容的 NUMERIC 或 DECIMAL
-
类型处理器 StringTypeHandler
- Java 类型:java.lang.String
- JDBC 类型:CHAR, VARCHAR
-
类型处理器 ClobReaderTypeHandler
- Java 类型:java.io.Reader
- JDBC 类型:-
-
类型处理器 ClobTypeHandler
- Java 类型:java.lang.String
- JDBC 类型:CLOB, LONGVARCHAR
-
类型处理器 NStringTypeHandler
- Java 类型:java.lang.String
- JDBC 类型:NVARCHAR, NCHAR
-
类型处理器 NClobTypeHandler
- Java 类型:java.lang.String
- JDBC 类型:NCLOB
-
类型处理器 BlobInputStreamTypeHandler
- Java 类型:java.io.InputStream
- JDBC 类型:-
-
类型处理器 ByteArrayTypeHandler
- Java 类型:byte[]
- JDBC 类型:数据库兼容的字节流类型
-
类型处理器 BlobTypeHandler
- Java 类型:byte[]
- JDBC 类型:BLOB, LONGVARBINARY
-
类型处理器 DateTypeHandler
- Java 类型:java.util.Date
- JDBC 类型:TIMESTAMP
-
类型处理器 DateOnlyTypeHandler
- Java 类型:java.util.Date
- JDBC 类型:DATE
-
类型处理器 TimeOnlyTypeHandler
- Java 类型:java.util.Date
- JDBC 类型:TIME
-
类型处理器 SqlTimestampTypeHandler
- Java 类型:java.sql.Timestamp
- JDBC 类型:TIMESTAMP
-
类型处理器 SqlDateTypeHandler
- Java 类型:java.sql.Date
- JDBC 类型:DATE
-
类型处理器 SqlTimeTypeHandler
- Java 类型:java.sql.Time
- JDBC 类型:TIME
-
类型处理器 ObjectTypeHandler
- Java 类型:Any
- JDBC 类型:OTHER 或未指定类型
-
类型处理器 EnumTypeHandler
- Java 类型:Enumeration Type
- JDBC 类型:VARCHAR 或任何兼容的字符串类型,用来存储枚举的名称(而不是索引序数值)
-
类型处理器 EnumOrdinalTypeHandler
- Java 类型:Enumeration Type
- JDBC 类型:任何兼容的 NUMERIC 或 DOUBLE 类型,用来存储枚举的序数值(而不是名称)。
-
类型处理器 SqlxmlTypeHandler
- Java 类型:java.lang.String
- JDBC 类型:SQLXML
-
类型处理器 InstantTypeHandler
- Java 类型:java.time.Instant
- JDBC 类型:TIMESTAMP
-
类型处理器 LocalDateTimeTypeHandler
- Java 类型:java.time.LocalDateTime
- JDBC 类型:TIMESTAMP
-
类型处理器 LocalDateTypeHandler
- Java 类型:java.time.LocalDate
- JDBC 类型:DATE
-
类型处理器 LocalTimeTypeHandler
- Java 类型:java.time.LocalTime
- JDBC 类型:TIME
-
类型处理器 OffsetDateTimeTypeHandler
- Java 类型:java.time.OffsetDateTime
- JDBC 类型:TIMESTAMP
-
类型处理器 OffsetTimeTypeHandler
- Java 类型:java.time.OffsetTime
- JDBC 类型:TIME
-
类型处理器 ZonedDateTimeTypeHandler
- Java 类型:java.time.ZonedDateTime
- JDBC 类型:TIMESTAMP
-
类型处理器 YearTypeHandler
- Java 类型:java.time.Year
- JDBC 类型:INTEGER
-
类型处理器 MonthTypeHandler
- Java 类型:java.time.Month
- JDBC 类型:INTEGER
-
类型处理器 YearMonthTypeHandler
- Java 类型:java.time.YearMonth
- JDBC 类型:VARCHAR 或 LONGVARCHAR
-
类型处理器 JapaneseDateTypeHandler
- Java 类型:java.time.chrono.JapaneseDate
- JDBC 类型:DATE
咱们能够通过源码查看内置的类型别名的注册信息。
具体源码门路在 org.apache.ibatis.type.TypeHandlerRegistry # TypeHandlerRegistry():
public TypeHandlerRegistry() {register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
register(Reader.class, new ClobReaderTypeHandler());
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(InputStream.class, new BlobInputStreamTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());
// mybatis-typehandlers-jsr310
if (Jdk.dateAndTimeApiExists) {Java8TypeHandlersRegistrar.registerDateAndTimeHandlers(this);
}
// issue #273
register(Character.class, new CharacterTypeHandler());
register(char.class, new CharacterTypeHandler());
}
从 3.4.5 开始,MyBatis 默认反对 JSR-310(日期和工夫 API), 能够在以上源码上看到新增反对。
个别,你能够重写已有的类型处理器,
或依据业务须要创立你本人的类型处理器,
以解决不反对的类型或非规范的类型。
具体做法为:
1、实现 org.apache.ibatis.type.TypeHandler
接口;
2、继承 org.apache.ibatis.type.BaseTypeHandler
类。
自身 BaseTypeHandler 类作为抽象类就曾经实现了 TypeHandler 接口。
所以咱们看到接口 TypeHandler 定义了四个办法:
public interface TypeHandler<T> {void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
从办法名 setParameter 和 getResult 咱们就能够晓得,是产生在预编译时设置参数(增删改查传入参数)与查问后果集后转换为 Java 类型时,类型处理器发挥作用。
具体实现如下,先自定义类型处理器类 MyExampleTypeHandler:
// MyExampleTypeHandler.java
@MappedJdbcTypes(JdbcType.VARCHAR)
public class MyExampleTypeHandler extends BaseTypeHandler<String> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {ps.setString(i, parameter);
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {return rs.getString(columnName);
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return rs.getString(columnIndex);
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return cs.getString(columnIndex);
}
}
自定义类已设定:JdbcType.VARCHAR 与 String 类做映射转换(注解和泛型已体现)。
其次,在外围配置文件中设置类型处理器:
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.mybatis.example.MyExampleTypeHandler"/>
</typeHandlers>
或者不应用注解形式的话,勾销 @MappedJdbcTypes(JdbcType.VARCHAR) 注解,间接在 xml 配置中指定 jdbcType 与 javaType 映射:
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler jdbcType="VARCHAR" javaType="string" handler="org.mybatis.example.MyExampleTypeHandler"/>
</typeHandlers>
记住,typeHandler 的配置形式优先级高于注解配置形式。
这里,自定义类型处理器将会笼罩已有的解决 Java String 类型的属性以及 VARCHAR 类型的参数和后果的类型处理器,根本以上步骤就曾经自定了 JdbcType.VARCHAR 与 String类做映射转换。
其实到这里,咱们根本也就实现了类型处理器的自定义转换,然而有一种状况,就是咱们心愿咱们自定义的类型处理器只解决某一个 Java 实体中的 JdbcType.VARCHAR 与 String 类映射转换,其它实体的解决还是应用零碎内置的转换,很简略,咱们只须要把以上两步都去掉,在自定义类型解决类的注解 @javaType 和 @MappedJdbcTypes 都移除,配置文件中把 typehandler 属性配置移除,间接在映射文件中编写:
<resultMap id="MyResultMap" type="com.panshenlian.pojo.User">
<!-- id 为 int 类型,然而没指定自定义类型处理器,不受影响 -->
<id column="id" property="id" />
<!-- username 为 String 类型,然而没指定自定义类型处理器,不受影响 -->
<id column="username" property="username" />
<!-- password 为 String 类型,然而没指定自定义类型处理器,不受影响 -->
<id column="password" property="password" />
<!-- birthday 为 String 类型,指定自定义类型处理器,受影响!-->
<id column="birthday" property="birthday" typeHandler="com.panshenlian.typeHandler.MyStringHandler"/>
</resultMap>
<select id="findAll" resultType="com.panshenlian.pojo.User" resultMap="MyResultMap">
select * from User
</select>
User 实体参考:
package com.panshenlian.pojo;
/**
* @Author: panshenlian
* @Description: 用户实体
* @Date: Create in 2:08 2020/12/07
*/
public class User {
private int id;
private String username;
private String password;
private String birthday;
public int getId() {return id;}
public void setId(int id) {this.id = id;}
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
public String getBirthday() {return birthday;}
public void setBirthday(String birthday) {this.birthday = birthday;}
}
最终自定义类型处理器,只会对 birthday 字段产生影响,其余字段均不受影响。
自定义类型处理器很灵便,只有当指定对应的 Java 类型和 Jdbc 类型时,处理器才会具体失效,否则 Mybatis 会默认匹配零碎内置的类型处理器。
另外,当咱们自定义很多类型处理器时,零碎反对配置包扫描的形式查找类型处理器:
<!-- mybatis-config.xml -->
<typeHandlers>
<package name="org.mybatis.example"/>
</typeHandlers>
留神在应用主动发现性能的时候,只能通过注解形式来指定 JDBC 的类型。
你能够创立可能解决多个类的泛型类型处理器。为了应用泛型类型处理器,须要减少一个承受该类的 class 作为参数的结构器,这样 MyBatis 会在结构一个类型处理器实例的时候传入一个具体的类。
//GenericTypeHandler.java
public class GenericTypeHandler<E extends MyObject> extends BaseTypeHandler<E> {
private Class<E> type;
public GenericTypeHandler(Class<E> type) {if (type == null) throw new IllegalArgumentException("Type argument cannot be null");
this.type = type;
}
...
解决枚举类型
若想映射枚举类型 Enum
,则须要从 EnumTypeHandler
或者 EnumOrdinalTypeHandler
中抉择一个来应用。
比如说咱们想存储取近似值时用到的舍入模式。默认状况下,MyBatis 会利用 EnumTypeHandler
来把 Enum
值转换成对应的名字。
留神
EnumTypeHandler
在某种意义上来说是比拟特地的,其它的处理器只针对某个特定的类,而它不同,它会解决任意继承了Enum
的类。不过,咱们可能不想存储名字,相同咱们的 DBA 会保持应用整形值代码。那也一样简略:在配置文件中把
EnumOrdinalTypeHandler
加到typeHandlers
中即可,这样每个RoundingMode
将通过他们的序数值来映射成对应的整形数值。
<!-- mybatis-config.xml -->
<typeHandlers>
<typeHandler handler="org.apache.ibatis.type.EnumOrdinalTypeHandler" javaType="java.math.RoundingMode"/>
</typeHandlers>
但要是你想在一个中央将 Enum
映射成字符串,在另外一个中央映射成整形值呢?
主动映射器(auto-mapper)会主动地选用 EnumOrdinalTypeHandler
来解决枚举类型,所以如果咱们想用一般的 EnumTypeHandler
,就必须要显式地为那些 SQL 语句设置要应用的类型处理器。
下一篇文章咱们才开始介绍映射器 mapper.xml 文件,如果你首次浏览映射器概念,可能须要先跳过这里先去理解 mapper.xml 文件配置,再回头过去看。
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.apache.ibatis.submitted.rounding.Mapper">
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode"/>
</resultMap>
<select id="getUser" resultMap="usermap">
select * from users
</select>
<insert id="insert">
insert into users (id, name, funkyNumber, roundingMode) values (#{id}, #{name}, #{funkyNumber}, #{roundingMode}
)
</insert>
<resultMap type="org.apache.ibatis.submitted.rounding.User" id="usermap2">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="funkyNumber" property="funkyNumber"/>
<result column="roundingMode" property="roundingMode" typeHandler="org.apache.ibatis.type.EnumTypeHandler"/>
</resultMap>
<select id="getUser2" resultMap="usermap2">
select * from users2
</select>
<insert id="insert2">
insert into users2 (id, name, funkyNumber, roundingMode) values (#{id}, #{name}, #{funkyNumber}, #{roundingMode, typeHandler=org.apache.ibatis.type.EnumTypeHandler}
)
</insert>
</mapper>
留神,这里的 select 语句强制应用 resultMap
来代替 resultType
。
5、objectFactory(对象工厂)
每次 MyBatis 创立后果对象的新实例时,它都会应用一个对象工厂(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 constructorArgs) {return super.create(type, constructorArgTypes, constructorArgs);
}
public void setProperties(Properties properties) {super.setProperties(properties);
}
public boolean isCollection(Class type) {return Collection.class.isAssignableFrom(type);
}
}
<!-- mybatis-config.xml -->
<objectFactory type="org.mybatis.example.ExampleObjectFactory">
<property name="someProperty" value="100"/>
</objectFactory>
ObjectFactory 接口很简略,它蕴含两个创立用的办法,一个是解决默认构造方法的,另外一个是解决带参数的构造方法的。最初,setProperties 办法能够被用来配置 ObjectFactory,在初始化你的 ObjectFactory 实例后,objectFactory 元素体中定义的属性会被传递给 setProperties 办法。
失常状况下咱们不须要应用到,或者说不倡议应用,除非业务上的确须要对一个非凡实体初始结构做一个默认属性值配置等解决,其余状况不举荐应用,防止产生不可控危险。
6、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 外围 API 的时候或者独自介绍自定义插件的时候会具体阐明,这里大家能够先大抵理解,包含数据分页、操作日志加强、sql 性能监控等都能够通过插件实现,不过会存储革新的危险,毕竟这些都是外围的 API。
这四大类中办法具体能够通过查看每个办法的签名来发现,或者间接查看 MyBatis 发行包中的源代码。如果你想做的不仅仅是监控办法的调用,那么你最好相当理解要重写的办法的行为。因为在试图批改或重写已有办法的行为时,很可能会毁坏 MyBatis 的外围模块。这些都是更底层的类和办法,所以应用插件的时候要特地当心。
通过 MyBatis 提供的弱小机制,应用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦挡的类,办法,参数(因为有多态的状况)即可。
// ExamplePlugin.java
@Intercepts({
@Signature(
type= Executor.class,
method = "update",
args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {private Properties properties = new Properties();
public Object intercept(Invocation invocation) throws Throwable {
// implement pre processing if need
Object returnObject = invocation.proceed();
// implement post processing if need
return returnObject;
}
public void setProperties(Properties properties) {this.properties = properties;}
}
<!-- mybatis-config.xml -->
<plugins>
<plugin interceptor="org.mybatis.example.ExamplePlugin">
<property name="someProperty" value="100"/>
</plugin>
</plugins>
下面的插件将会拦挡在 Executor 实例中所有的“update”办法调用,这里的 Executor 是负责执行底层映射语句的外部对象。
笼罩配置类「审慎应用,存在危险」
除了用插件来批改 MyBatis 外围行为以外,还能够通过齐全笼罩配置类来达到目标。只需继承配置类后笼罩其中的某个办法,再把它传递到 SqlSessionFactoryBuilder.build(myConfig) 办法即可。再次重申,这可能会极大影响 MyBatis 的行为,务请慎之又慎。
7、environments(环境配置)
MyBatis 能够配置成适应多种环境,这种机制有助于将 SQL 映射利用于多种数据库之中,现实情况下有多种理由须要这么做。例如,开发、测试和生产环境须要有不同的配置;或者想在具备雷同 Schema 的多个生产数据库中应用雷同的 SQL 映射。还有许多相似的应用场景。
不过要记住:只管能够配置多个环境,但每个 SqlSessionFactory 实例只能抉择一种环境。
所以,如果你想连贯两个数据库,就须要创立两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就须要三个实例,依此类推,记起来很简略:
每个数据库对应一个 SqlSessionFactory 实例。
为了指定创立哪种环境,只有将它作为可选的参数传递给 SqlSessionFactoryBuilder 即可。能够承受环境配置的两个办法签名是:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, properties);
如果疏忽了环境参数,那么将会加载默认环境,如下所示:
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, properties);
environments 元素定义了如何配置环境。
<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>
留神一些关键点:
- 默认应用的环境 ID(比方:default=”development”)。
- 每个 environment 元素定义的环境 ID(比方:id=”development”)。
- 事务管理器的配置(比方:type=”JDBC”)。
- 数据源的配置(比方:type=”POOLED”)。
默认环境和环境 ID 顾名思义。环境能够随便命名,但务必保障默认的环境 ID 要匹配其中一个环境 ID。
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”):
- JDBC – 这个配置间接应用了 JDBC 的提交和回滚设施,它依赖从数据源取得的连贯来治理事务作用域。
- MANAGED – 这个配置简直没做什么。它从不提交或回滚一个连贯,而是让容器来治理事务的整个生命周期(比方 JEE 应用服务器的上下文)。默认状况下它会敞开连贯。然而一些容器并不心愿连贯被敞开,因而须要将 closeConnection 属性设置为 false 来阻止默认的敞开行为。例如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
如果你正在应用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会应用自带的管理器来笼罩后面的配置。这两种事务管理器类型都不须要设置任何属性。它们其实是类型别名,换句话说,你能够用 TransactionFactory 接口实现类的全限定名或类型别名代替它们。
public interface TransactionFactory {default void setProperties(Properties props) { // 从 3.5.2 开始,该办法为默认办法
// 空实现
}
Transaction newTransaction(Connection conn);
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
在事务管理器实例化后,所有在 XML 中配置的属性将会被传递给 setProperties() 办法。你的实现还须要创立一个 Transaction 接口的实现类,这个接口也很简略:
public interface Transaction {Connection getConnection() throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;
Integer getTimeout() throws SQLException;}
应用这两个接口,你能够齐全自定义 MyBatis 对事务的解决。
数据源(dataSource)
dataSource 元素应用规范的 JDBC 数据源接口来配置 JDBC 连贯对象的资源。
大多数 MyBatis 应用程序会按示例中的例子来配置数据源。尽管数据源配置是可选的,但如果要启用提早加载个性,就必须配置数据源。
有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”):
UNPOOLED– 这个数据源的实现会每次申请时关上和敞开连贯。尽管有点慢,但对那些数据库连贯可用性要求不高的简略应用程序来说,是一个很好的抉择。性能体现则依赖于应用的数据库,对某些数据库来说,应用连接池并不重要,这个配置就很适宜这种情景。UNPOOLED 类型的数据源仅仅须要配置以下 5 种属性:
driver
– 这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能蕴含的数据源类)。url
– 这是数据库的 JDBC URL 地址。username
– 登录数据库的用户名。password
– 登录数据库的明码。defaultTransactionIsolationLevel
– 默认的连贯事务隔离级别。defaultNetworkTimeout
– 期待数据库操作实现的默认网络超时工夫(单位:毫秒)。查看java.sql.Connection#setNetworkTimeout()
的 API 文档以获取更多信息。
作为可选项,你也能够传递属性给数据库驱动。只需在属性名加上“driver.”前缀即可,例如:
driver.encoding=UTF8
这将通过 DriverManager.getConnection(url, driverProperties) 办法传递值为
UTF8
的encoding
属性给数据库驱动。
POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连贯对象组织起来,防止了创立新的连贯实例时所必须的初始化和认证工夫。这种解决形式很风行,能使并发 Web 利用疾速响应申请。
除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源:
poolMaximumActiveConnections
– 在任意工夫可存在的流动(正在应用)连贯数量,默认值:10poolMaximumIdleConnections
– 任意工夫可能存在的闲暇连接数。poolMaximumCheckoutTime
– 在被强制返回之前,池中连贯被检出(checked out)工夫,默认值:20000 毫秒(即 20 秒)poolTimeToWait
– 这是一个底层设置,如果获取连贯破费了相当长的工夫,连接池会打印状态日志并从新尝试获取一个连贯(防止在误配置的状况下始终失败且不打印日志),默认值:20000 毫秒(即 20 秒)。poolMaximumLocalBadConnectionTolerance
– 这是一个对于坏连贯容忍度的底层设置,作用于每一个尝试从缓存池获取连贯的线程。如果这个线程获取到的是一个坏的连贯,那么这个数据源容许这个线程尝试从新获取一个新的连贯,然而这个从新尝试的次数不应该超过poolMaximumIdleConnections
与poolMaximumLocalBadConnectionTolerance
之和。默认值:3(新增于 3.4.5)poolPingQuery
– 发送到数据库的侦测查问,用来测验连贯是否失常工作并筹备承受申请。默认是“NO PING QUERY SET”,这会导致少数数据库驱动出错时返回失当的谬误音讯。poolPingEnabled
– 是否启用侦测查问。若开启,须要设置poolPingQuery
属性为一个可执行的 SQL 语句(最好是一个速度十分快的 SQL 语句),默认值:false。poolPingConnectionsNotUsedFor
– 配置 poolPingQuery 的频率。能够被设置为和数据库连贯超时工夫一样,来防止不必要的侦测,默认值:0(即所有连贯每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时实用)。
JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中应用,容器能够集中或在内部配置数据源,而后搁置一个 JNDI 上下文的数据源援用。这种数据源配置只须要两个属性:
initial_context
– 这个属性用来在 InitialContext 中寻找上下文(即,initialContext.lookup(initial_context))。这是个可选属性,如果疏忽,那么将会间接从 InitialContext 中寻找 data_source 属性。data_source
– 这是援用数据源实例地位的上下文门路。提供了 initial_context 配置时会在其返回的上下文中进行查找,没有提供时则间接在 InitialContext 中查找。
JNDI 可了解是一种仿 windows 注册表模式的数据源。
和其余数据源配置相似,能够通过增加前缀“env.”间接把属性传递给 InitialContext。比方:
env.encoding=UTF8
这就会在 InitialContext 实例化时往它的构造方法传递值为 UTF8
的 encoding
属性。
你能够通过实现接口 org.apache.ibatis.datasource.DataSourceFactory
来应用第三方数据源实现:
public interface DataSourceFactory {void setProperties(Properties props);
DataSource getDataSource();}
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory
可被用作父类来构建新的数据源适配器,比方上面这段插入 C3P0 数据源所必须的代码:
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {public C3P0DataSourceFactory() {this.dataSource = new ComboPooledDataSource();
}
}
为了令其工作,记得在配置文件中为每个心愿 MyBatis 调用的 setter 办法减少对应的属性。上面是一个能够连贯至 PostgreSQL 数据库的例子:
<dataSource type="org.myproject.C3P0DataSourceFactory">
<property name="driver" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql:mydb"/>
<property name="username" value="postgres"/>
<property name="password" value="root"/>
</dataSource>
8、databaseIdProvider(数据库厂商标识)
MyBatis 能够依据不同的数据库厂商执行不同的语句,这种多厂商的反对是基于映射语句中的 databaseId
属性。MyBatis 会加载带有匹配以后数据库 databaseId
属性和所有不带 databaseId
属性的语句。如果同时找到带有 databaseId
和不带 databaseId
的雷同语句,则后者会被舍弃。为反对多厂商个性,只有像上面这样在 mybatis-config.xml 文件中退出 databaseIdProvider
即可:
<databaseIdProvider type="DB_VENDOR" />
databaseIdProvider 对应的 DB_VENDOR 实现会将 databaseId 设置为 DatabaseMetaData#getDatabaseProductName()
返回的字符串。因为通常状况下这些字符串都十分长,而且雷同产品的不同版本会返回不同的值,你可能想通过设置属性别名来使其变短:
<databaseIdProvider type="DB_VENDOR">
<property name="SQL Server" value="sqlserver"/>
<property name="DB2" value="db2"/>
<property name="Oracle" value="oracle" />
</databaseIdProvider>
在提供了属性别名时,databaseIdProvider 的 DB_VENDOR 实现会将 databaseId 设置为数据库产品名与属性中的名称第一个相匹配的值,如果没有匹配的属性,将会设置为“null”。在这个例子中,如果 getDatabaseProductName()
返回“Oracle (DataDirect)”,databaseId 将被设置为“oracle”。
你能够通过实现接口 org.apache.ibatis.mapping.DatabaseIdProvider
并在 mybatis-config.xml 中注册来构建本人的 DatabaseIdProvider:
public interface DatabaseIdProvider {default void setProperties(Properties p) { // 从 3.5.2 开始,该办法为默认办法
// 空实现
}
String getDatabaseId(DataSource dataSource) throws SQLException;
}
9、mappers(映射器)
既然 MyBatis 的行为曾经由上述元素配置完了,咱们当初就要来定义 SQL 映射语句了。但首先,咱们须要通知 MyBatis 到哪里去找到这些语句。在主动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的方法是间接通知 MyBatis 到哪里去找映射文件。你能够应用绝对于类门路的资源援用,或齐全限定资源定位符(包含 file:///
模式的 URL),或类名和包名等。例如:
<!-- 应用绝对于类门路的资源援用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 应用齐全限定资源定位符(URL)-->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 应用映射器接口实现类的齐全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全副注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
XML 映射文件
在 XML 外围配置文件介绍中,咱们介绍了映射文件 mapper.xml 的引入。
对于 Mapper 具体的映射配置文件,是 Mybatis 最简单、最外围的组件,其中的标签内容体系也是特地详实,包含它的参数类型、动静 SQL、定义 SQL、缓存信息等等,咱们在下一篇文章中再进行梳理探讨,这里咱们简略引出。
总结
本来我打算把外围配置文件和映射器 mapper 文件放一块讲,然而发现内容太多太多了,根本外围配置文件就曾经讲得有点拖堂了,尽管这几大顶级标签应用起来曾经毫不费力。SQL 映射器配置文件,咱们后续更新,这块根本是和咱们日常打交道最高频的操作。
本篇完,本系列下一篇咱们讲《Mybatis 系列全解(五):全网最全!详解 Mybatis 的 Mapper 映射文件》。
BIU ~ 文章继续更新,微信搜寻「潘潘和他的敌人们」第一工夫浏览,随时有惊喜。本文会在 GitHub https://github.com/JavaWorld 收录,热腾腾的技术、框架、面经、解决方案,咱们都会以最美的姿态第一工夫送达,欢送 Star。