MyBatis是一个开源的数据持久层框架,它内部封装了通过JDBC访问数据库的操作,支持普通的SQL查询、存储过程和高级映射,几乎消除了所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis作为持久层框架,其主要思想是将程序中大量SQL语句剥离出来,配置在配置文件中,实现SQL的灵活配置。这样做的好处是将SQL与程序代码分离,可以在不修改程序代码的情况下,直接在配置文件中修改SQL。Mybatis通过简单的XML或者注解进行配置和原始映射,将实体类和SQL语句之间建立映射关系,是一种半自动化的ORM实现。
接口式编程
原生: Dao ----> DaoImpl
mybatis : Mapper —> xxMapper.xml
SqlSession代表了和数据库的一次会话用完必须关闭
SqlSession和connection一样,都是非线程安全的,每次使用都应该去获取新的对象
mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象
两个重要的配置文件
mybatis的全局配置文件,包含数据库连接池信息,事务管理器信息等,系统运行环境
sql映射文件,保存了每一个sql语句的映射信息
将sql抽取出来,交给程序员来编写,区别于hibernate的黑箱操作
核心配置文件标签顺序
properties : 引入外部properties配置文件的内容
resource : 引入类路径下的资源
url : 引入网络路径或者磁盘路径下的资源
settings : 包含很多重要的设置项
setting : 用来设置每一个设置项
name : 设置项名
value : 设置项取值
如 :
驼峰命名规范映射
typeAliases : 别名处理器,可以为我们的java类型起别名 别名区分大小写
typeAlias : 为某个java类型起别名
type : 指定要起别名的类型全类名,默认别名就是类名小写
alias : 指定新的别名 一般不设置
package : 为某个包下的所有类批量起别名
name : 指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名,默认还是类名小写)
注意 : 如果包下和子包下有两个类名相同的类,这时候会报错,可以使用@Alias注解再类上设置别名
typeHandlers : 类型处理器
environments : 环境,mybatis可以配置多种环境 default:指定使用某种环境,可以达到快速切换环境
environment : 配置一个具体的环境信息 必须有两个标签, id : 代表当前环境的唯一标识
transactionManager : 事务管理器,只做了解,以后事务都交给spring管理的
type : 事务管理器的类型
JDBC(JdbcTransactionFactory) : 使用了JDBC的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围
MANAGED(ManagedTransactionFactory) : 不提交或回滚一个连接、让容器来管理事务的整个生命周期
自定义事务管理器 : 实现TransactionFactory接口,type指定为全类名
dataSource : 数据源
type : 数据源类型
UNPOOLED : UnpooledDataSourceFactory 不使用连接池
POOLED : PooledDataSourceFactory 使用连接池
JNDI : JndiDataSourceFactory
自定义数据源 : 实现DataSourceFactory接口,type 全类名
推荐 : 再定义外部数据源文件的时候 带一个前缀 如: jdbc.driver 防止冲突
databaseIdProvider : 支持多数据库厂商
type : DB_VENDOR VendorDatabaseIdProvider
作用就是得到数据厂商的标识,mybatis就能根据数据厂商标识来执行不同的sql
mappers : 将sql映射注册到全局配置中
mapper : 注册一个sql映射
resource : 引用类路径下的sql映射文件
url : 引用网络路径下或者磁盘路径下的sql映射文件
class : 直接引用(注册)接口(写接口的全类名)
有sql映射文件,映射文件名必须和接口同名,并且放在与接口同一目录下没有sql映射文件,所有的sql都是利用注解写在接口上
推荐 :
比较重要的,复杂的Dao接口我们来写sql映射文件
不重要的,简单的Dao接口,为了开发快速可以使用注解
package : 批量注册 如果是Maven项目,需要配置静态资源映射
name : mapper所在包
mapper
namespace : 名称空间,指定为接口的全类名
cache : 命名空间的二级缓存配置
cache-ref : 其他命名空间缓存配置的引用
select : 映射查询语句
insert : 映射插入语句
update: 映射修改语句
delete : 映射删除语句
insert、update、delete属性设置
id: 唯一标识符
parameterType : 要传入语句的参数的完全限定名或别名,这个属性是可选的,因为MyBatis可以通过TypeHandler推断出具体传入语句的参数类型 默认值为unset
flushCache : true:任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:true(对应增删改语句)
timeout : 在抛出异常之前,驱动程序等待数据库返回请求结果的秒数,默认值为unset(依赖驱动)
useGeneratedKeys :(仅对insert和update有用)这会令Mybatis使用JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键 默认值为false
keyProperty: 仅对insert和update有用)唯一标识一个属性,mybatis会通过getGeneratedKeys的返回值或者通过insert语句的selectKey子元素设置它的键值,默认unset
databaseId : 如果配置了databaseIdProvider,mybatis会加载所有的不带databaseId或匹配当前databaseId的语句,如果带或者不带的语句都有,则不带的会被忽略
主键生成方式
useGeneratedKeys=“true” : 使用自增主键获取主键值策略
keyProperty : 指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性
注意 : Oracle不支持自增 : Oracle使用序列来模拟自增
每次插入的数据的主键是从序列中拿到的值
selectKey
keyProperty : selectKey语句结果应该被设置的目标属性
resultType : 结果的类型,mybatis允许任何简单类型作为主键类型,包括字符串
order :
BEFORE: 首先选择主键,设置keyProperty然后执行插入语句
AFTER: 先执行插入语句,然后是selectKey元素
参数传递
单个参数: 可以接收基本类型,对象类型,集合类型的值,这种情况,mybatis可直接使用这个参数,不需要经过任何处理
多个参数: 任意多个参数,都会被封装成一个map
key: 就是 param1…paramN,或者参数的索引也可以
value: 传入的参数值
命名参数: 使用@Param注解为参数起一个名字 如@Param(“id”)
多个参数会被封装成map
key: 使用@Param注解指定的值
value: 参数值
POJO: 如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo
取值 : #{属性名}
Map: 如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们可以出传入map
TO: 如果多个参数不是业务模型中的数据,但是经常要使用,推荐编写一个TO(Transfer Object)数据传输对象
特殊一点的
public Employee selEmp(@Param("id")Integer id, String lastName);
取值: id :#{id / param1} lastName:#{param2}
public Employee selEmp(Integer id, Employee emp); // 如果emp加了 @Param("e") 注解
取值:id:#{param1} lastName:没有加注解#{param2.lastName} 加了注解#{e.lastName}
特别注意 : 如果是Collection(List Set) 类型或者是数组
也会特殊处理,也是吧传入的list或数组封装在map中
key: Conllection:conllection List :list 数组 : array
public Employee selEmpById(List ids);
取出第一个值:#{list[0]}
参数值的获取
#{} :可以获取map中值或者pojo对象属性的值
${} :可以获取map中值或者pojo对象属性的值
区别
#{}:是以预编译的形式,将参数设置到sql语句中,PreparedStatement防止sql注入
${}
:取出的值,直接拼接在sql语句中,有安全问题
大多数情况下,我们去参数的值都应该使用#{}
原生JDBC不支持占位符的地方我们就可以使用${}进行取值
如:按照年份 分表拆分
select * from ${year}_salary where xxx;
select * from tbl order by ${f_name} ${order};
#{}更丰富的用法
规定参数的一些规则
javaType: java类型
jdbcType: jdbc类型
mode: 存储过程
numericScale: 保留几位小数
resultMap: 结果类型
typeHandler: 类型处理器
jabcTypeName
expression:表达式,未来准备支持的功能
jdbcType通常需要在某种特定的条件下被设置
在外面数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理,比如Oracle(报错)
JdbcType OTHER : 无效的类型 : 因为mybatis对所有的null都映射的是原生jdbc里的OTHER类型 oracle不能正确处理
由于全局配置中: jdbcTypeForNull = OTHER; oracle不支持 两种办法
1. #{可能为空的字段,jdbcType=NULL}
2. jdbcTypeForNull = NULL;
select属性
**id:**唯一标识符 用来引用这条语句,需要和接口的方法名一致
parameterType: 参数类型
resultType: 返回值类型,别名或者全类名,如果返回的是集合,定义集合中元素的类型,不能和resultMap同时使用
resultMap: 外部resultMap的命名引用
flushCache: true:任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被情况默认为false
useCache: true:将会导致本条语句的结果被二级缓存,默认值:对select元素为true
timeout: 在抛出异常之前,驱动程序等待数据库返回请求结果的秒数,默认值unset
databaseId: 如果配置了databaseIdProvider,mybatis会加载所有的不带databaseId或匹配当前databaseId的语句,如果带或者不带的语句都有,则不带的会被忽略
resultMap : 自定义结果集映射
constructor: 类在实例化时,用来注入结果到构造方法中
idArg: ID参数,标记结果作为ID可以帮助提高整体性能
arg: 注入到构造方法的一个普通结果
id: 一个ID结果,标记结果作为ID可以帮助提高整体性能
result: 注入到字段或JavaBean属性的普通结果
association: 定义关联对象的封装规则
select: 表名当前属性是调用select指定的方法查出的结果
column: 指定将哪一列的值传递给这个方法
整个流程: 使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性
collection: 定义关联集合类型的属性封装规则
property: 关联的属性
ofType: 指定集合里元素类型
select: 表明当前属性是调用select指定的方法查出结果
column: 指定将哪一列的值传给这个方法
column传递 多列{key=value} key取名为接收方法的参数名
动态sql
动态sql是mybatis强大特性之一,极大的简化我们拼装SQL的操作
if:判断
test: 判断表达式,从参数中取值进行判断,遇见特殊符号应该使用转义字符
choose(when、otherwise): 分支选择,带了break的switch-case
trim:
prefix: 给拼串后的整个字符串加一个前缀
prefixOverrides: 前缀覆盖,去掉整个字符串前面多余的字符串
suffix: 后缀,给拼串后的整个字符串加一个后缀
suffixOverrides: 去掉整个字符串后面多余的字符
where:
会将标签中多出来的and或者or去掉,只能去掉第一个多出来的
set:
封装修改条件
foreach:
collection: 指定要遍历的集合
list类型的参数会特殊处理 封装在map中,map的key就叫list
item: 将当前遍历出的元素赋值给指定的遍历
separator: 每个元素之间的分隔符
open: 遍历出所有结果,拼接一个开始字符
close: 遍历出所有结果,拼接一个结束的字符
index: 索引,遍历list的时候index就是所有,item就是当前值
遍历map的时候,index表示的就是map的key,item就是map的值
可以用于批量插入
bind: 可以将OGNL表达式的值绑定到一个变量中,方便后来引用这个变量的值
sql: 抽取可重用的sql片段 可以方便后面引用
sql抽取: 经常将要查询的列名或者插入用的列名抽取出来方便引用
include来引用以抽取的sql
include:还可以自定一些property,sql标签内部就能使用自定义的属性
取值${prop} 不能使用#{}这种方式
include: 引用外部的sql
refid: 引用的sql片段id
MyBatis 包含一个非常强大的查询缓存特性,它可以非 常方便地配置和定制。缓存可以极大的提升查询效率
mybatis系统中默认定义了两级缓存
一级缓存:(本地缓存): sqlSession级别的缓存,一级缓存是一致开启的,SqlSession级别的一个Map
与数据库同一次会话期间查询到的数据会放在本地缓存
以后如果需要获取相同的数据,之间从缓存中拿,没必要再去查询数据库
本地缓存不能被关闭,但可以调用clearCache()来清空本地缓存,或者改变缓存的作用域
在mybatis3.1之后,可以在全局配置文件中配置缓存的作用域
localCacheScope: 本地缓存作用域 (一级缓存 SESSION)当前会话的所有数据保存在会话缓存中
STATEMENT : 可以禁用一级缓存
一级缓存失效的情况
sqlSession不同
sqlSession相同,查询条件不同(当前一级缓存中还没有这个数据)
sqlSession相同,两次查询之间执行了增删改操作,(这次增删改可能对当前数据又影响)
sqlSession相同,手动清除了一级缓存(缓存清空了)
二级缓存:(全局缓存): sqlSession级别的缓存,一个namespace对应一个二级缓存
工作机制
一个会话,查询一条数据,这个数据会被放在当前会话的一级缓存中
如果当前会话关闭,那么一级缓存中的数据会被保存到二级缓存中,新的会话查询信息,就可以参照二级缓存中的内容
不同的namespace查出的数据会放在自己对应的缓存中(Map)
效果: 数据会从二级缓存中获取
查出的数据都会被默认先放在一级缓存中
只有会话提交或者关闭以后,一级缓存中的数据才会被放到二级缓存中
使用步骤:
开启全局二级缓存配置:
去每个mapper.xml中配置使用二级缓存
pojo需要实现序列化接口
和缓存有关的设置 / 属性
cacheEnabled = true; false,关闭缓存(二级缓存关闭 一级缓存一直可用)
每个select标签都有useCache=true
false: 不适用缓存(一级缓存依然使用,二级缓存不使用)
每个增删改标签的flushCache=true默认都是true(一级二级都会清除)重点
增删改执行完后就会清除缓存
测试:flushCache=“true” 一级缓存清空,二级缓存也会被清除
select标签,flushCache=“false” 默认为false不会清除缓存,如果设置为true每次查询之后都会清空缓存
sqlSession.clearCache(): 只是清除当前session的一级缓存
localCacheScope: 本地缓存作用域
SESSION: 当前会话的所有数据保存在会话缓存中
STATEMENT: 可用禁用一级缓存
在mapper中的配置
eviction: 缓存的回收策略(缓存中的内容超了之后,吧哪些内容删掉)
LRU: 最近最少使用的,移除最长时间不被使用的对象
FIFO: 先进先出,按对象 进入缓存的顺序来移除他们
SOFT: 软引用,移除基于垃圾回收器状态和软引用规则的对象
WEAK: 弱引用,更积极地移除基于垃圾收集器状态和弱引用规则的对象
默认是LRU
flushInterval: 缓存刷新间隔
缓存多长时间清空一次,默认不清空,设置一个毫秒值
readOnly: 缓存是否只读
true: 只读,mybatis任务所有从缓存中获取数的操作都是只读操作,不会修改数据
mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户,(如果用户改变了,缓存中的值也会改变,不安全但是速度快)
false: 非只读,mybatis认为获取的数据可能会被修改
mybatis会利用序列化与反序列化的技术克隆一份新的数据给你,安全、速度慢,默认为false
size: 缓存存放多少元素
tyep: 指定自定义缓存的全类名,实现Cache接口即可