01-Mybatis篇(新版)
概述

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了[google code](https://baike.baidu.com/item/google code/2346604),并且改名为MyBatis 。2013年11月迁移到Github。
Mybatis特性
MyBatis 是一款优秀的持久层框架
它支持自定义 SQL、存储过程以及高级映射。
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
什么是持久层
数据持久化
持久化就是将程序的数据在持久状态和瞬时状态转化的过程
内存:断电即失
数据库(jdbc),io文件持久化。
为什么需要持久化?
有一些数据,不能丢失
内存太贵了
持久层
持久层:完成持久化工作的代码块
搭建MyBatis
相关依赖
创建MyBatis的核心配置文件
习惯:一般命名为 mybatis-config.xml
作用:配置链接数据库的环境、配置MyBatis
放置位置:src/main/resources
创建mapper接口
命名规则:POJO实体类的名字 + Mapper。
相当于DAO,但是不用创建实现类,MyBatis会创建代理类,并执行映射文件当中的SQL。
创建MyBatis的映射文件
Mapper 接口当中的一个抽象方法对应映射文件当中的一个SQL语句。
起名规则:POJO名字 + Mapper.xml
放置位置:src/main/resources/UserMapper.xml
通过junit测试功能
从开始到创建 SqlSessionFactory 只用创建一次即可,因此可以单独封装即可。
openSession() 获得 SqlSession 默认是不自动提交事务,因此需要自己手动提交。
加入log4j日志功能
日志级别:FATAL(致命)> ERROR(错误)>WARN(警告)INFO(信息)> DEBUG(调试)。
相关依赖
放置位置:resources/log4j.xml
核心配置文件详解
mybatis-config.xmlmybatis的配置文件包含了会深深影响mybatis行为的设置和属性信息
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
mybatis-config.xml
environments
可以配置多个环境,比如测试环境和开发环境 ;
使用id区分,不能重复
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:
提示 如果正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
数据源(dataSource)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
POOLED:使用数据库连接池
UNPOOLED:不使用数据库连接池,链接直接重新创建
JNDI:表示使用上下文当中的数据源(了解下)
属性(properties)
可以通过
properties属性来实现引用配置文件这些属性都是可外部配置且可动态替换的,既可以在典型的java属性文件中配置,亦可通过
properties的元素子元素来传递。
比如,引入jdbc.properties文件
在核心配置文件中,必须按照顺序进行配置
重写核心配置文件
mybatis-config.xml
如果两个文件有同一个字段,优先使用外部配置文件
类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。
仅用于 XML 配置,意在降低冗余的全限定类名书写。
在 Mapper.xml 文件中使用
设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
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
Specifies an sql provider class that holds provider method (Since 3.5.6). This class apply to the type(or value) attribute on sql provider annotation(e.g. @SelectProvider), when these attribute was omitted.
A type alias or fully qualified class name
Not set
一个配置完整的 settings 元素的示例如下:
其他配置
mybatis-generator-coreo
mybatis-plus
通用mapper
映射器(Mappers)

MapperRegistry:注册绑定我们的Mapper文件;
方式一
方式二:使用class进行注册
接口和配置文件必须同名
接口和配置文件必须在同一个包下
方式三:使用扫描包进行注册绑定,与上相同,但是能够注册多个
接口和配置文件,同名,就基本不会有问题。
生命周期与作用域

不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder
一旦创建了 SqlSessionFactory,就不再需要它了
局部变量
SqlSessionFactory
说白了就是可以想象为︰数据库连接池
sqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
因此 SqlSessionFactory 的最佳作用域是应用作用域。
最简单的就是使用单例模式或者静态单例模式。
SqlSession
连接到连接池的一个请求!
sqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
用完之后需要赶紧关闭,否则资源被占用

这里面的每一个Mapper,就代表一个具体的业务!
获取参数值的两种方式
绑定namespace
namespace中的包名和Dao/Mapper接口中的包名要一致。
单个字面量类型的参数
dao层
UserMapper.xml
‼️ 注意 ${} + 单引号的问题。其中传入的参数通过#{param} 或者 '${param}'传入,并且param的定义名称与Dao层的参数名称一样。
id:对应的namespace中的方法名resultType:Sql语句执行的返回值parameterType:指定传入的参数类型
注意,#{}是预编译处理,可以防止SQL注入;${}仅仅是字符串替换。
多个字面量类型的参数
当 Mapper 接口中有多个参数的时候,MyBatis 会创建Map ,并使用 paramX 或 argX 为Key,参数值为 Value , 且两者均可混合使用。
dao层
UserMapper.xml
map集合类型的参数
dao层
UserMapper.xml
实体类类型的参数
必须有 getter / setter;单个POJO会形成一个Map,属性名作为Key,getter 后的值作为 value。
!!属性只跟 getter/setter 有关系。
dao层
UserMapper.xml
使用@Param标识参数
其会替换argXX,即只能用 {username, param1, password, param2 } 这四个在配置文件当中。
dao层
UserMapper.xml
List<POJO>
详见动态SQL - foreach。
MyBatis的各种查询功能
查询一个实体类对象
注意设置 resultType 即可,可以使用别名。
当SQL语句返回多条记录的时候,会报:TooManyResultException 的错误。
dao层
UserMapper.xml
查询一个List集合
注意设置 resultType 依然为 POJO 的类型。
dao层
UserMapper.xml
查询单个数据
dao层
UserMapper.xml
查询一条数据为map集合
查询的结果没有对应的实体类的时候,就可以使用Map集合。
resultType 设置成 map 即可。
注意:查询为null 的字段是不会放到Map集合里面。
dao层
UserMapper.xml
也可以使用 Map 存放多条记录,需要使用到 @MapKey 注解。
dao层
UserMapper.xml
数据
查询多条数据为map集合
dao层
UserMapper.xml
特殊SQL的执行
模糊查询
dao层
UserMapper.xml
批量删除 in
即传入的参数数量不确定,这里直接先构成一个字符串,再使用拼接方式传入即可。
dao层
UserMapper.xml
动态设置表名
表查询的字段相同,但是表名称不相同。
dao层
UserMapper.xml
获取自增的主键
场景:比如一个班级表和一个学生表,在一个事务当中先创建一个班级(使用的是自增的主键)然后在这个班级里面添加若干的学生。
dao层
UserMapper.xml
自定义映射resultMap
字段名 和 属性名不一致(可以尝试别名处理)
一对一 或 一对多 的关系查询
处理字段和属性的映射关系
开启下划线→小驼峰的配置,在 mybatis-config.xml 文件当中添加如下配置。
接下来使用,使用 ResltMap , 注意 resultMap 和 resultType 是二选一的。
多对一映射处理
建立数据库
例子:多个学生对应一个老师
测试环境搭建
导入lombok
新建实体类 Teacher、Student
Pojo实体类
Teacher
Student
建立Mapper接口
Teacher
Student
建立 StudentMapper.xml 文件
按照结果嵌套处理
一对多映射处理
Pojo实体类
Student
Teacher
建立 TeacherMapper.xml
按照结果嵌套处理
按照查询嵌套处理
小结
关联- association【多对一】
集合- collection 【一对多】
javaType & ofType
JavaType 用来指定实体类中属性的类型
ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型!
注意点
保证SQL的可读性,尽量保证通俗易懂
注意一对多和多对一中,属性名和字段的问题!
如果问题不好排查错误,可以使用日志,建议使用Log4j
动态SQL
根据传入的参数动态的决定最后执行的SQL语句。
if
choose, when, otherwise (switch)
MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
foreach(批量插删,IN)
经常用于批量添加 和 批量删除。
批量插入
批量删除
SQL片段
将重复的SQL代码抽取出来被多个语句重复使用。
MyBatis的缓存
MyBatis的一级缓存
一级缓存是SqlSession级别的缓存(即同一个链接),通过同一个SqlSession查询的数据。
以下四种情况会导致一级缓存失效:
不同SqlSession对应不同一级缓存。(即不同SqlSession,即使是相同查询条件也无用)。
同一个SqlSession但是查询条件不同。
同一个SqlSession 两次查询期间执行了任何一次针对此表增删改操作。
同一个SqlSession两次查询期间手动清空了缓存。
MyBatis的二级缓存
开启的四个条件
SqlSessionFactory 级别的,多个SqlSession可以共享。
核心配置文件,设置全局属性配置 cacheEnabled="true", 默认为 true,不需要设置。
在映射文件中设置<cache/>
二级缓存必须是在 SQLSession 关闭或提交之后有效。(即SQLSession关闭或提交后,一级缓存当中的数据才会保存到一级缓存中)。
实体类必须实现 Serializable 接口。
失效
任意一次增删改会清空二级缓存。(唯一情况)。
二级缓存的相关配置
在mapper配置文件中添加的cache标签可以设置一些属性:
eviction属性:缓存回收策略,默认的是LRU
LRU - 最近最少使用的:移除最长时间不被使用的对象
FIFO - 先进先出:按对象进入缓存的顺序来移除它们。
SOFT - 软引用:移除基于垃圾回收器状态和软引用规则的对象
WEAK - 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
flushInterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
size属性:引用数目,正整数
代表缓存最多可以存储多少哥对象,太大容易导致内存溢出
readOnly属性:只读,true/false
true:只读缓存,会给所有调用则返回缓存对象的相同实例。因此这些对象不能被修改,这提供了很重要的性能优势。
MyBatis缓存查询的顺序
先查询二级缓存,因为二级缓存当中可能会有其他线程已经查询出来的数据。
二级缓存没有命中,则再查询一级缓存。
一级缓存也没有命中,则执行查询数据库。
SQLSession关闭之后,一级缓存当中的数据会写入到二级缓存。
整合第三方缓存EHCache(了解)
Ehcache是一种广泛使用的开源Java分布式缓存。
要在程序中使用encache,导入包:
在指定mapper中指定实现ehcache缓存
分页功能
使用Limit分页
使用mybatis实现分页:
dao层
UserMapper.java
UserMapper.xml
测试
RowBounds分页
dao层
UserMapper.java
UserMapper.xml
测试
分页插件
PageHelper

插件地址:https://pagehelper.github.io/
LomBok
Project Lombok 是一个 Java 库,可自动插入您的编辑器并构建工具,为您的 Java 增添趣味。 永远不要再编写另一个 getter 或 equals 方法,通过一个注释,您的类就有一个功能齐全的构建器,自动化您的日志变量等等。
使用步骤
在IDEA中安装Lombok插件
在项目中导入lombok的jar包

@Data:无参构造,get、set、tostring、hashcode、equals
如果使用lombok会导致代码可读性低。
使用注解开发
案例
dao层
mybatis-config.xml
但是在处理复杂的语句上,就有点力不从心了。
CRUD
我们可以在工具类
查询
UserMapper.java
添加
UserMapper.java
注意:insert into 表名括号中的字段与数据库中的相同,values中的字段与实体类的字段相同。
删除
UserMapper.java
更新
UserMapper.java
拓展:#{}能够很大程度上防止sql注入,${}无法阻止
关于@Param()注解
基本类型的参数或者String类型,需要加上
引用类型不需要加
如果只有一个基本类型的话,可以忽略,但是建议大家都加上!
我们在SQL中引用的就是我们这里的
@Param()中设定的属性名!
最后更新于
这有帮助吗?
