# 一、MyBatis基础
# 1.1 MyBatis简介
ORM(object relational mapping)对象关系映射
POJO(Plain Old Java Objects)普通老式 Java 对象
MyBatis是一个持久层框架/半自动的ORM。
它支持自定义 SQL、存储过程以及高级映射。
是一种从SQL到POJO的模型,它需要我们提供SQL、映射管理XML、POJO。
# 1.2 Mybatis缓存机制
MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。
缓存可以极大的提升查询效率,减轻数据库压力,提高数据库性能。
MyBatis系统中默认定义了两级缓存,分别是一级缓存和二级缓存。
- 默认情况下,只有一级缓存开启。
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
- 为了提高扩展性,MyBatis定义了缓存接口Cache,我们可以通过实现Cache接口来自定义二级缓存。
# 1)一级缓存
一级缓存,SqlSession级别的缓存,也称为本地缓存,缓存的数据只在SqlSession
内有效。
一级缓存一直是开启的。
它实质上就是sqlSession级别的一个Map,在操作数据库的时候需要先创建 SqlSession 会话对象,在对象中有一个 HashMap 用于存储缓存数据,此 HashMap 是当前会话对象私有的,别的 SqlSession 会话对象无法访问。
具体流程
- 第一次执行 select 完毕,会将查到的数据写入 SqlSession 内的 HashMap 中缓存起来;
- 第二次执行 select 会从缓存中查数据,如果 select 同传参数一样,那么就能从缓存中返回数据,不用去数据库了,从而提高了效率。
一级缓存失效的情况
没有使用到当前一级缓存的情况,效果就是还要再向数据库发出查询。
- sqlSession不同。
- sqlSession相同,查询条件不同(当前一级缓存中还没有这个数据)。
- sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响),实际上,这个是因为每个增删改查都有标签flushCache,增删改默认为flushCache=“true”,即执行完后就清除一级缓存和二级缓存。
- sqlSession相同,手动清除了一级缓存(缓存清空,session.clearCache(),注意,该方法只清除当前session的一级缓存)。
# 2)二级缓存
二级缓存,namespace级别的缓存,也称为全局缓存,一个namespace
对应一个二级缓存。
二级缓存默认是没有开启的,需要在 setting 全局参数中配置开启二级缓存。
开启二级缓存步骤
1、conf.xml 配置,全局变量开启二级缓存。
<setting name="cacheEnabled" value="true"/>
默认是false(关闭二级缓存)
2、在 具体某一Mapper.xml中配置(XxxMapper.xml )。
<cache></cache>
表示当前mapper下的所有语句开启二级缓存。
cache标签的属性说明
evictio:缓存的回收策略
LRU
- 最近最少使用的,移除最长时间不被使用的对象。FIFO
- 先进先出,按对象进入缓存的顺序来移除他们。SOFT
- 软引用,移除基于垃圾回收器状态和引用规则的对象。WEAK
- 弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。默认的是LRU。
flushInterval:缓存刷新间隔
缓存多长时间清空一次,默认不清空,可设置一个毫秒值。
readOnly:是否只读
true
:只读,MyBatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据,所以为了加快速度,mybatis直接将数据在缓存中的引用交给用户。这种方式不安全,但速度快。false
:非只读,MyBatis觉得获取的数据肯能会被修改,所以MyBatis会利用序列化和反序列化的技术克隆一份新的数据给你。这种方式安全,但是速度慢。因此,此时需要将所有需要在二级缓存中存放的对象都实现序列化接口。
size:缓存存放多少元素
type:指定自定义缓存的全类名
我们一般使用默认的,也可以自定义类实现Cache接口,然后在这个属性上写上自定义实现类的全类名,就可以使用自定义的二级缓存。
缓存的相关配置
每个select标签都有属性useCache,默认为true。
true:使用缓存;false:不使用缓存。
注意:控制的是二级缓存的使用与否,一级缓存一直可用。
每个增删改查都有标签flushCache。
增删改默认为flushCache=“true”,即执行完后就清除一级缓存和二级缓存;
查询默认为flushCache=“false”,即执行完后不清除一级和二级缓存。
sqlSession.clearCache():只清除当前session的一级缓存。
# 缓存使用
当执行SQL查询时,
1、先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用;
2、如果二级缓存没有命中,再查询一级缓存;
3、如果一级缓存也没有命中,则查询数据库。
# 1.3 注解使用
注解 | 出处 | 使用场景 | 作用 |
---|---|---|---|
@MapperScan | 在启动类中用 | 是将MyBatis所需的接口(Mapper包路径下)扫描装配到Spring IoC容器中 | |
@Reposity | Spring提供 | 在Mapper接口中 | 使用该注解将对象交由Spring容器来管理,Spring会将该接口识别为Bean |
@Mapper | MaBatis提供 | 在Mapper接口中 | 添加了该注解的接口将被扫描为Spring的Bean装配到IoC容器中 |
说明:
Ant通配符的3种风格:
?
:匹配文件名中的一个字符; eg: com/test/entity? 匹配 com/test/entityaa*
: 匹配文件名中的任意字符; eg: com/*/entity 匹配 com/test/entity**
: 匹配文件名中的多重路径; eg: com/**/entity 匹配 com/test/test1/entity
# 二、MyBatis-Plus
# 2.1 MyBatis-Plus简介
MyBatis-Plus(简称 MP)是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。
官方
- MyBatis-Plus官网:https://baomidou.com (opens new window)
- MyBatis-Plus官方代码:https://gitee.com/baomidou/mybatis-plus (opens new window)
- MyBatis-Plus官网代码案例:https://github.com/baomidou/mybatis-plus-samples (opens new window)
MyBatis-Plus教程
- MyBatis-Plus 入门 - 视频教程 - 慕课网 (opens new window)
- MyBatis-Plus 进阶 - 视频教程 - 慕课网 (opens new window)
- MyBatis-Plus + SpringBoot实现简单权限管理 - 视频教程 - 慕课网 (opens new window)
# 三、FQA
# update方法赋null值
问题描述:
Mybatis-Plus
使用updateById()
将字段更新为null
时,未成功赋值。
问题解读:
mybatis-plus FieldStrategy 有三种策略:
IGNORED
:0 忽略NOT_NULL
:1 非 NULL,默认策略NOT_EMPTY
:2 非空
而默认更新策略是NOT_NULL
:即通过接口更新数据时,数据为NULL值时将不更新进数据库。
解决方法:
1、设置全局的field-strategy
mybatis-plus:
global-config:
#字段策略 0:"忽略判断",1:"非 NULL 判断",2:"非空判断"
field-strategy: 0
2
3
4
说明:配置文件为全局性配置,会对所有的字段都忽略判断,如果一些字段不想要修改,但是传值的时候没有传递过来,就会被更新为null,可能会影响其他业务数据的正确性。
2、对某个字段设置单独的field-strategy
根据具体情况,在需要更新为null的字段上,设置忽略策略。
@TableField(updateStrategy = FieldStrategy.IGNORED)
private String dutyJson;
2
然后在更新代码中,我们直接使用mybatis-plus中的updateById方法便可以更新成功。
说明:如果需要这样处理的字段较多,那么就需要涉及对各个字段上都添加该注解。
3、使用UpdateWrapper方式更新(推荐使用)
使用mybatisplus
包下BaseMapper
类中的update
方法,即可更新null
值。
package com.baomidou.mybatisplus.core.mapper;
public interface BaseMapper<T> extends Mapper<T> {
/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
}
2
3
4
5
6
7
8
9
10
11
使用案例:
public boolean delete(Long userId) {
LambdaUpdateWrapper<SysUser> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(SysUser::getId, userId)
.set(SysUser::getStatus, null)
.set(SysUser::getLevel, null)
;
return sysUserMapper.update(null, lambdaUpdateWrapper) > 0;
}
2
3
4
5
6
7
8