MyBatis简介
•
MyBatis
是支持定制化
SQL
、存储过程以及高级映射的优秀的持久层框架。
•
•
MyBatis
避免了几乎所有的
JDBC
代码和手动设置参数以及获取结果集。
•
•
MyBatis
可以使用简单的
XML
或注解用于配置和原始映射,将接口和
Java
的
POJO
(
Plain Old Java Objects
,普通的
Java
对象)映射成数据库中的记录
.
MyBatis历史
•
原
是
A
pache
的一个开源项目
iBatis
, 2010
年
6
月这个项目
由
A
pache
S
oftware
F
oundation
迁移到
了
Google
C
ode
,随着开发团队转投
Google Code
旗下
,
iBatis3.x
正式更名为
MyBatis
,代码于
2013
年
11
月迁移到
Github
(下载地址见后)。
•
•
iBatis
一
词来源于“
internet
”和“
abatis
”的组合,是一个基于
Java
的持久层框架
。
iBatis
提供
的持久层框架包括
SQL Maps
和
Data Access Objects
(
DAO
)
为什么要使用MyBatis?
•
MyBatis
是一个半自动化的持久化层框架。
•
JDBC
–
SQL
夹在
Java
代码块里,耦合度高导致硬编码
内伤
–
维护不易且实际开发需求中
sql
是有变化,频繁修改的情况多
见
•
Hibernate
和
JPA
–
长难复杂
SQL
,对于
Hibernate
而言处理也不容易
–
内部自动生产的
SQL
,不容易做特殊优化。
–
基于全映射的全自动框架
,大量字段的
POJO
进行部分映射时比较困难。
导致数据库性能下降
。
•
对
开发人员而言,核心
sql
还是需要自己
优化
•
sql
和
java
编码分开,功能边界清晰,一个专注业务、一个专注数据
。
去哪里找MyBatis?•https://github.com/mybatis/mybatis-3/
![](https://i-blog.csdnimg.cn/blog_migrate/f3b713aee2c0ab84bc8271c9e9c96bde.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4b613f91a2975419d40423c583c34067.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a541176a7bd7513616413b8a08580a52.png)
MyBatis操作数据库
•
1
、
创建
MyBatis
全局配置文件
–
MyBatis
的全局配置文件包含了影响
MyBatis
行为甚深的设置(
settings
)和属性(
properties
)信息、如数据库连接池信息等。指导着
MyBatis
进行工作。我们可以参照官方文件的配置示例
。
•
2
、
创建
SQL
映射文件
–
映射文件的作用就相当于是定义
Dao
接口的实现类如何工作。这也是我们使用
MyBatis
时编写的最多的文件。
测试
•
SqlSessionFactoryBuilder
创建
SqlSessionFactory
![](https://i-blog.csdnimg.cn/blog_migrate/227b1fb726b52dae2a570983a1140892.png)
使用SqlSessionFactory获取sqlSession对象。一个SqlSession对象代表和数据库的一次会话。
![](https://i-blog.csdnimg.cn/blog_migrate/623fc70db41b9f449d7bde7712e06603.png)
使用SqlSession根据方法id进行操作
![](https://i-blog.csdnimg.cn/blog_migrate/73603de7abd5c9a3247d8e19d00ecbbf.png)
使用SqlSession获取映射器进行操作
![](https://i-blog.csdnimg.cn/blog_migrate/36968c82af78680695265abc0b29d55c.png)
SqlSession
•
SqlSession
的实例
不是线程安全
的,因此是不能被共享的
。
•
•
SqlSession
每次
使用完成后需要正确关闭
,这个关闭操作是必须的
•
•
SqlSession
可以直接调用方法的
id
进行数据库操作,但是我们一般还是推荐使用
SqlSession
获取到
Dao
接口的代理
类,执行代理对象的
方法,可以更安全的进行类型检查操作
三、MyBatis-全局配置文件
•
MyBatis
的配置文件包含了影响
MyBatis
行为甚深的设置(
settings
)和
属性(
properties
)信息。文档的顶层结构如下
:
•
•
configuration
配置
•
environment
环境变量
•
transactionManager
事务管理器
•
dataSource
数据源
在Eclipse中引入XML的dtd约束文件,方便编写XML的时候有提示
![](https://i-blog.csdnimg.cn/blog_migrate/17abc2f457d5bda342bd06cd565f2f35.png)
properties属性
![](https://i-blog.csdnimg.cn/blog_migrate/3d6df89233f39380139969bc49c66c27.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4b3b00bb323ca71bf37541bd43c7bf9e.png)
•
如果
属性在不只一个地方进行了配置,那么
MyBatis
将按照下面的顺序来加载
:
–
在
properties
元素体内指定的属性首先被读取。
–
然后根据
properties
元素中的
resource
属性读取类路径下属性文件或根据
url
属性指定的路径读取属性文件,并覆盖已读取的同名属性
。
–
最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。
settings设置
•
这是
MyBatis
中极为重要的调整设置,它们会改变
MyBatis
的运行时行为
。
![](https://i-blog.csdnimg.cn/blog_migrate/2fa67dc8897b710272ff4fe1a9a5efe0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/eaa321fd3a01165213b08dcfa872b460.png)
typeAliases别名处理器
•
类型别名是为
Java
类型设置一个短的名字,可以方便我们引用某个类。
![](https://i-blog.csdnimg.cn/blog_migrate/e53d7daf6e45d04b920d4f0b9a80ef67.png)
- 类很多的情况下,可以批量设置别名这个包下的每一个类创建一个默认的别名,就是简单类名小写。
![](https://i-blog.csdnimg.cn/blog_migrate/cc09d0cb64ba140206689c3fc5ed8fe2.png)
•也可以使用@Alias注解为其指定一个别名
![](https://i-blog.csdnimg.cn/blog_migrate/c618103e51c396a9ddbeea826e6b4fdd.png)
值得注意的是,MyBatis已经为许多常见的 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 |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
typeHandlers类型处理器
•
无论是
MyBatis
在预处理语句(
PreparedStatement
)中设置一个参数时,还是从结果集中取出一个值时, 都会
用类型处理器将获取的值以合适的方式转换成
Java
类型
。
类型处理器 | Java 类型 | JDBC 类型 |
BooleanTypeHandler | java.lang.Boolean, boolean | 数据库兼容的 BOOLEAN |
ByteTypeHandler | java.lang.Byte, byte | 数据库兼容的 NUMERIC 或 BYTE |
ShortTypeHandler | java.lang.Short, short | 数据库兼容的 NUMERIC 或 SHORT INTEGER |
IntegerTypeHandler | java.lang.Integer, int | 数据库兼容的 NUMERIC 或 INTEGER |
LongTypeHandler | java.lang.Long, long | 数据库兼容的 NUMERIC 或 LONG INTEGER |
FloatTypeHandler | java.lang.Float, float | 数据库兼容的 NUMERIC 或 FLOAT |
DoubleTypeHandler | java.lang.Double, double | 数据库兼容的 NUMERIC 或 DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | 数据库兼容的 NUMERIC 或 DECIMAL |
StringTypeHandler | java.lang.String | CHAR, VARCHAR |
日期类型的处理
•
日期和时间的处理
,
JDK1.8
以前一直是个头疼的问题。我们通常使用
JSR310
规范领导者
Stephen
Colebourne
创建的
Joda
-Time
来操作。
1.8
已经实现全部的
JSR310
规范了。
•
日期时间处理上,我们可以使用
MyBatis
基于
JSR310
(
Date and Time API
)编写的各种日期
时间类型处理器
。
•
MyBatis3.4
以前的版本需要我们手动注册这些处理器,以后的版本都是自动注册的
![](https://i-blog.csdnimg.cn/blog_migrate/a741aa9e0a408db6d8ca6b9bed300cc8.png)
自定义类型处理器
•
我们可以重写类型处理器或创建自己的类型处理器来处理不支持的或非标准的类型
。
•
•
步骤:
•
1
)、实现
org.apache.ibatis.type.TypeHandler
接口
或者继承
org.apache.ibatis.type.BaseTypeHandler
•
2
)、指定其映射某个
JDBC
类型(可选操作)
•
3
)、在
mybatis
全局配置文件中
注册
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)
environments环境
•
MyBatis
可以配置多种环境,比如开发、测试和生产环境需要有不同的配置
。
•
•
每种环境使用一个
environment
标签进行配置并指定唯一
标识符
•
•
可以通过
environments
标签中的
default
属性指定一个环境的标识符来快速的切换
环境
environment-指定具体环境
•
id
:指定当前环境的唯一标识
•
transactionManager
、和
dataSource
都必须有
![](https://i-blog.csdnimg.cn/blog_migrate/5d93011ddf9e81c8a59bd6765d8b3bba.png)
transactionManager
•
type
:
JDBC | MANAGED |
自定义
–
JDBC
:使用了
JDBC
的提交和回滚设置,依赖于从数据源得到的连接来管理事务
范围。
JdbcTransactionFactory
–
MANAGED
:不提交或回滚一个连接、让容器来管理事务的整个生命周期(比如
JEE
应用服务器的上下文)。
ManagedTransactionFactory
–
自定义
:实现
TransactionFactory
接口,
type=
全类名
/
别名
dataSource
•
type
:
UNPOOLED | POOLED | JNDI |
自定义
–
UNPOOLED
:不使用连接
池,
UnpooledDataSourceFactory
–
POOLED
:使用连接池,
PooledDataSourceFactory
–
JNDI
: 在
EJB
或应用服务器这类容器中查找指定的数据源
–
自定义
:实现
DataSourceFactory
接口,定义数据源的获取方式。
–
•
实际开发中我们使用
Spring
管理数据源
,并进行事务控制的配置来
覆盖上述配置
databaseIdProvider环境
•
MyBatis
可以根据不同的数据库厂商执行不同的语句
。
•
Type
:
DB_VENDOR
–
使用
MyBatis
提供的
VendorDatabaseIdProvider
解析数据库厂商标识。也可以实现
DatabaseIdProvider
接口来自定义
。
•
Property-name
:数据库厂商标识
•
Property-value
:为标识起一个别名,方便
SQL
语句使用
databaseId
属性
引用
•
DB_VENDOR
–
会
通过
DatabaseMetaData#getDatabaseProductName
()
返回的字符串进行设置。由于通常情况下这个字符串都非常长而且相同产品的不同版本会返回不同的值,所以最好通过设置属性别名来使其变
短
•
•
MyBatis
匹配规则
如下:
–
1
、如果没有配置
databaseIdProvider
标签,那么
databaseId
=null
–
2
、如果配置了
databaseIdProvider
标签,使用标签配置的
name
去匹配数据库信息,匹配上设置
databaseId
=
配置指定的值,否则依旧为
null
–
3
、如果
databaseId
不为
null
,他只会找到配置
databaseId
的
sql
语句
–
4
、
MyBatis
会加载
不带 databaseId
属性和带有
匹配当前数据库databaseId 属性
的
所有语句
。如果同时找到带有 databaseId 和不带databaseId 的相同语句
,
则后者会被舍弃
。
mapper映射
•mapper逐个注册SQL映射文件
![](https://i-blog.csdnimg.cn/blog_migrate/94801acb18940f46cae4fac25b5cceec.png)
•
或者使用批量
注册
:
•
这种方式要求
SQL
映射文件名必须和接口名相同并且在同一目录下
•
MyBatis-映射文件
•
映射文件指导着
MyBatis
如何进行数据库增删改查,有着非常重要的
意义;
•
•
c
ache
–命名空间的
二级缓存配置
•
cache-ref
– 其他命名空间缓存配置的引用。
•
resultMap
–
自定义结果集映射
•
parameterMap – 已废弃!老式风格的参数
映射
•
sql
–
抽取
可重用语句块。
•
insert
– 映射插入语句
•
update
– 映射更新语句
•
delete
– 映射删除语句
•
select
– 映射查询语句
insert、update、delete元素
![](https://i-blog.csdnimg.cn/blog_migrate/9156ebb6fe23c20027061550d0cfcdb9.png)
主键生成方式
•
若数据库
支持自动生成主键
的字段(比如
MySQL
和
SQL Server
),则可以设置
useGeneratedKeys
=”true”
,然后再把
keyProperty
设置到目标属性上。
•
主键生成方式
•
而对于不支持自增型主键的数据库(例如
Oracle
),则可以使用
selectKey
子元素:
selectKey
元素将会首先运行
,
id
会被设置
,
然后插入语句会被调用
selectKey
![](https://i-blog.csdnimg.cn/blog_migrate/875774b6f9346e4f32af63b794c20e93.png)
参数(Parameters)传递
•
单个
参数
–
可以接受基本类型,对象类型,集合类型的值。这种情况
MyBatis
可直接使用这个参数,不需要经过任何处理
。
•
多
个参数
–
任意多个参数,都会被
MyBatis
重新包装成一个
Map
传入。
Map
的
key
是
param1
,
param2
,
0
,
1…
,值就是参数的值
。
•
命名参数
–
为参数使用
@Param
起一个名字,
MyBatis
就会将这些参数封装进
map
中,
key
就是我们自己指定的
名字
•
POJO
–
当这些参数属于我们业务
POJO
时,我们直接传递
POJO
•
Map
–
我们也可以封装多个参数为
map
,直接传递
参数处理
参数也可以指定一个特殊的数据类型:
![](https://i-blog.csdnimg.cn/blog_migrate/6481f749d9feb0948fcbbe547e8ea8d5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5dddc69d0bf4bd0e9a139ec0d8837d14.png)
javaType 通常可以从参数对象中来去确定
如果 null 被当作值来传递,对于所有可能为空的列,jdbcType 需要被设置
对于数值类型,还可以设置小数点后保留的位数:
mode 属性允许指定 IN,OUT 或 INOUT 参数。如果参数为 OUT 或 INOUT,参数对象属性的真实值将会被改变,就像在获取输出参数时所期望的那样。
•
参数位置支持的属性
–
javaType
、
jdbcType
、
mode
、
numericScale
、
resultMap、typeHandler、jdbcTypeName、expression
•
实际上
通常被设置的是
:
可能为空的列名指定 jdbcType
•
#{key}
:获取参数的值,预编译到
SQL
中。安全。
•
${key}
:获取参数的值,拼接到
SQL
中。有
SQL
注入问题。
ORDER BY ${name}
select元素
•
Select
元素来定义查询操作。
•
Id
:唯一
标识符。
–
用来
引用这条语句,需要和接口的方法名一致
•
parameterType
:参数类型
。
–
可以
不传,
MyBatis
会根据
TypeHandler
自动
推断
•
resultType
:
返回值类型
。
–
别名或者全类名,如果返回的是
集合,定义
集合中元素的类型。不能和
resultMap
同时使用
![](https://i-blog.csdnimg.cn/blog_migrate/252e2a4b562bae3b863570c607fa2a21.png)
自动映射
•
1
、全局
setting
设置
–
autoMappingBehavior
默认是
PARTIAL
,开启自动映射的功能。唯一的要求是列名和
javaBean
属性名
一致
–
如果
autoMappingBehavior
设置为
null
则会取消自动
映射
–
数据库字段命名规范,
POJO
属性符合驼峰命名法,如
A_COLUMN
à
aColumn
,我们可以
开启自动驼峰命名规则映射功能
,
mapUnderscoreToCamelCase
=true
。
•
2
、
自定义
resultMap
,
实现高级
结果集映射。
resultMap
•
constructor -
类在实例化时
,
用来注入结果到构造方法中
–
idArg
- ID
参数
;
标记结果作为
ID
可以帮助提高整体效能
–
arg
-
注入到构造方法的一个普通结果
•
id
–
一个
ID
结果
;
标记结果作为
ID
可以帮助提高整体效能
•
result
–
注入到字段或
JavaBean
属性的普通结果
•
association
–
一个复杂的类型关联
;
许多结果将包成这种类型
–
嵌入结果映射
–
结果映射自身的关联
,
或者参考一个
•
collection
–
复杂类型的
集
–
嵌入结果映射
–
结果映射自身的集
,
或者参考一个
•
discriminator –
使用结果值来决定使用哪个结果映射
–
case –
基于某些值的结果映射
•
嵌入结果映射
–
这种情形结果也映射它本身
,
因此可以包含很多
相同
的元素
,
或者它可以参照一个外部的结果映射。
id & result
•id 和 result 映射一个单独列的值到简单数据类型(字符串,整型,双精度浮点数,日期等)的属性或字段。
![](https://i-blog.csdnimg.cn/blog_migrate/67f15f0d73be41ee4ce00c7296e03d7d.png)
association
•
复杂对象映射
•
POJO
中的属性可能会是一个对象
•
我们可以使用联合查询,并以级联属性的方式封装对象。
•
使用
association
标签定义对象的封装规则
association-嵌套结果集
![](https://i-blog.csdnimg.cn/blog_migrate/29168b601f1650769bd3e798631941a7.png)
association-分段查询
![](https://i-blog.csdnimg.cn/blog_migrate/8cfc8234a2ac8cc0e2821620842e44d7.png)
select:调用目标的方法查询当前属性的值
column:将指定列的值传入目标方法
association-分段查询&延迟加载
开启延迟加载和属性按需加载
![](https://i-blog.csdnimg.cn/blog_migrate/2fd3699a639337b28a37d9b364708613.png)
•
旧版本的
MyBatis
需要额外的支持包
–
asm-3.3.1.jar
–
cglib-2.2.2.jar
Collection-集合类型&嵌套结果集
![](https://i-blog.csdnimg.cn/blog_migrate/4dc9c21931cb38493b4dc05c935e4ac4.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d9d376e1b6a136f8508843964e2680e7.png)
Collection-分步查询&延迟加载
![](https://i-blog.csdnimg.cn/blog_migrate/e29aae5cf8c8967ddc8fb08ae7e9563b.png)
扩展-多列值封装map传递
•
分步查询
的时候通过
column
指定,将对应的列的数据传递过去,我们有时需要传递多列数据
。
•
使用
{key1=column1,key2=column2…}
的
形式
•
association
或者
collection
标签的
fetchType
=eager/lazy
可以覆盖全局的延迟加载策略,指定
立即加载(
eager
)
或者
延迟加载(
lazy
)