mybatis-plus
Mybatis&Mybatis Plus
MP官网
mybatis开发流程
crud: 编写实体类-》 编写Controller -》 编写Service -》 编写DAO -》 编写XML文件。
Mybatis与MP
MP是一个Mybatis的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发、提高效率而生。
mybatis默认解决单表的crud,可以靠 mybatis generator(简称MBG,用来生成单表的mapper,xml等)自动生成,但是MBG有一个缺点,表结构发生改变的时候,重新生成会覆盖掉原来的,所以就无法直接在生成的xml上改。使用时要把生成的mapper和xml放在某目录,自定义的mapper和xml放在另一个目录。
MP
pom.xml添加依赖
<!-- jdbc -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatisPlus 和 springboot整合 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
application.yml配置文件
# 配置端口
server:
port: 8081
spring:
# 配置数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8
username: root
password: root
#type: com.alibaba.druid.pool.DruidDataSource
# 配置最新全局配置文件,MybatisPlus一些配置可以配置在里面
# 注意: config-location和configuration不能共存!!!使用哪种方式全看个人喜好
mybatis-plus:
config-location: classpath:mybatis-config.xml
mybatis-plus:
configuration:
# 开启sql控制台日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# mybatis plus下划线转驼峰配置,默认是true
map-underscore-to-camel-case:true
# 配置文件配置 自定义sql的包扫描,有了这个xml文件里就用写包名了
mybatis-plus:
type-aliases-package: com.autumn.model
#配置全局默认主键类型,实体类就不用加@TableId(value="id",type=IdType=AUTO)
mybatis-plus:
global-config:
db-config:
id-type: auto
#逻辑删除
mybatis-plus:
global-config:
db-config:
# 如果java实体类没有加@TableLogic,则可以配置这个,推荐在配置文件配置
logic-delete-field: deleted
# 删除是1
logic-delete-value: 1
#未删除是0
logic-not-delete-value: 0
mybatis-config.xml
<?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>
<setting>
<!--控制台输出日志-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</setting>
</configuration>
分页配置
@Configuration
public class MybatisPlusPageConfig {
/*旧版本配置
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}*/
/*新的分页插件,一缓和二缓遵循mybatis的规则
* 需要设置MybatisCOnfiguration#useDeprecatedExecutor=false避免缓存出现问题
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor()
{
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//分页配置
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//乐观锁配置
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
扫描配置
启动类添加扫描接口注解@MapperScan
application.yml添加xml文件路径
#xml文件路径
mybatis-plus:
mapper-location:classpath:/mapper/**/*.xml
测试类
@SpringBootTest(classes=Application.class)
@Slf4j
class UnitTest{
@Autowired
private Service service;
@Test
public void Test selectList(){
List resultList = service.list();
log.info("结果集列表为:{}",resultList);
}
}
MP使用
实体类注解
@TableName: 定义表名
@TableId: 定义表的主键
@TableField: 定义列名,exist=false(非数据库字段)
业务类
QueryWrapper
eq 等于
ne 不等于
gt 大于
ge 大于等于
lt 小于
le 小于等于
or 拼接
between 两个值中间
notBetween 不在两个值中间
like 模糊匹配
notLike 不模糊匹配
likeLeft 左匹配
likeRight 右匹配
isNull 字段为空
in in查询
groupBy 分组
orderByAsc 升序
orderByDesc 降序
having having查询
select 查询指定的字段
select用与不用区别
用了select函数可以指定具体的字段,不用则是*,问题如下:
- 网络IO问题: 字段过多影响网络传输性能
- 索引问题: 指定字段可以不读data,直接用index里面的值返回结果
UpdateWrapper
eq 条件
set 需要修改的值
分页查询
//查询条件
QueryWrapper<UserDO> queryWrapper = new QueryWrapper();
queryWrapper.eq("id",4);
//第一页,每页10条
Page<UserDO> page = new Page<>(1,10);
//使用查询条件和分页插件查询
IPage<UserDO> iPage = userMapper.selectPage(page,queryWrapper);
log.info("总条数:{}",iPage.getTotal());
log.info("总页数:{}",iPage.getPages());
log.info("数据:{}",iPage.getRecords());
自定义xml
用法和mybatis一样,确保xml文件的namespace为接口类的全称。
ActiveRecord
ActiveRecord(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。
实体类继承Model即可。
业务逻辑比较简单,基本上和数据库中的表一一对应,适合简单的项目,不适合分布式和大型项目。只可做单表操作,当遇到跨表逻辑一般配合事务脚本(Transaction Script)。
如果对象间的关联越来越多,你的事务脚本越来越庞大,重复的代码越来越多,就不建议使用。
模型容易混乱,ActiveRecord保存了数据,使它有时候看上去像数据传输对象(DTO),但是ActiveRecord有数据库访问能力,所以分布式或者大型项目基本不用。
POJO
POJO: model/domain/dto/vo/bo/do
领域模型(domain model)是描述业务用例实现的对象模型。
领域模型分为以下几个概念:
VO(View Object) 通常是请求处理层传输的对象,它通过 Spring 框架的转换后,往往是一个JSON 对象。
DTO(Data Transfer Object)是远程调用对象,它是 RPC 服务提供的领域模型。
DO(Data Object):领域对象,此对象与数据库表结构一一对应,通过 DAO 层向上传输数据源对象。
PO (Persistent Object): 持久化对象,ORM映射的时候出现的概念,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系。
AO(Application Object):应用对象,在 Web 层与 Service 层之间抽象的复用对象模型,极为贴近展示层,复用度不高。
BO(Business Object):BO(Business Object),它是业务逻辑层封装业务逻辑的对象,一般情况下,它是聚合了多个数据源的复合对象。
乐观锁
实现方式:
- 版本号
每次拿数据时认为别人不会修改,更新的时候会判断别人是否去更新数据,通过版本判断,如果数据被修改了就拒绝更新。
- CAS
一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数
- 需要读写的内存值 V
- 进行比较的值 A
- 拟写入的新值 B
当且仅当V的值等于A时,CAS通过原子方式用新值B来更新V的值,否则不会执行swap操作(比较和替换是一个原子操作),一般情况下是一个自旋操作,即不断的重试,直到A=V时用B的值更新V。缺点是循环时间长时CPU开销很大,且只能保证一个共享变量的原子操作(可以把多个变量放在一个对象里来进行CAS操作,使用AtomicReference类来保证引用对象之间的原子性)。
Java里面大量使用CAS(Conmpare And Swap),CAS属于乐观锁,性能教悲观锁有很大的提高,AtomicXXX等原子类底层就是CAS实现,一定程度比synchronized好,因为synchronized是悲观锁。
总结:悲观锁适合写操作多的场景,乐观锁适合读操作多的场景,乐观锁的吞吐量会比悲观锁多。
数据库的乐观锁
大多是基于数据版本(Version)记录机制实现,即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库添加一个“version”字段来实现,读取数据时,此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本与数据库表对应的当前版本信息进行比对,如果提交的数据版本号大于数据库当前版本号,则予以更新,否则认为是过期数据。
MP乐观锁
配置
MybatisPlusPageConfig配置文件中新增乐观锁插件
//乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
表添加version列
在表中新增类型为int默认值为1的version字段
version int(11) default 1
实体添加version字段
在实体类中新增version字段,并使用@Version注解
@Version
private Integer version;
使用版本号乐观锁
先根据id获取该条记录(包含version)
修改某个字段后调用MP的updateById,发现库里的version字段加了1,生成的sql如下
update tbl set version = ? where id = ? and version = ?
mybatis-plus-generator
<!-- 代码自动生成依赖 begin -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<!-- velocity -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<!-- 代码自动生成依赖 end -->
java生成代码
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
public class CodeGenerator {
public static void main(String[] args) {
//1. 全局配置
GlobalConfig config = new GlobalConfig();
config.setActiveRecord(true) // 是否支持AR模式
.setAuthor("autumn") // 作者
.setOutputDir("D:\\projectname\\src\\main\\java") // 生成路径,这里要修改!!!!
.setFileOverride(false)// 文件覆盖
.setOpen(false) //是否打开输出目录
.setSwagger2(true)//是否打开swagger
.setIdType(IdType.AUTO) // 主键策略(共有4种 ,此处使用的是自增)
.setEnableCache(false) //是否开启二级缓存
.setServiceName("%sService") // 设置生成的service接口的名字的首字母是否为I
//IEmployeeService
.setBaseResultMap(true)// 是否生成xml文件中的ResultMap
.setBaseColumnList(true);// 是否生成xml文件中的ColumnList
//2. 数据源配置
DataSourceConfig dsConfig = new DataSourceConfig();
dsConfig.setDbType(DbType.MYSQL) // 设置数据库类型
.setDriverName("com.mysql.cj.jdbc.Driver")
.setUrl("jdbc:mysql://127.0.0.1:3306/swagger?useUnicode=true&characterEncoding=UTF-8&useSSL=false&" +
"serverTimezone=Hongkong&allowPublicKeyRetrieval=true")
.setUsername("root")
.setPassword("root");
//3. 策略配置
StrategyConfig stConfig = new StrategyConfig();
stConfig.setCapitalMode(true) //全局大写命名
//.setDbColumnUnderline(false) // 字段名是否使用下划线
.setNaming(NamingStrategy.underline_to_camel) // 数据库表映指定表名射到实体的命名策略
.setTablePrefix("at_")
.setEntityTableFieldAnnotationEnable(true)//是否生成字段注解
.setEntityLombokModel(true)//是否设置为lombok模型
.setInclude("user"); // 生成的表
//4. 包名策略配置
PackageConfig pkConfig = new PackageConfig();
pkConfig.setParent("com.autumn") //生成的包名,这里要修改!!!!
.setMapper("mapper")
.setService("service")
/*.setController("controller")*/
.setEntity("beans")
.setXml("mapper");
//5. 整合配置
AutoGenerator ag = new AutoGenerator();
ag.setGlobalConfig(config)
.setDataSource(dsConfig)
.setStrategy(stConfig)
.setPackageInfo(pkConfig).setTemplateEngine(new FreemarkerTemplateEngine());
//6. 执行
ag.execute();
}
}
生成的文件复制mapper接口、mapper.xml、model类,不要复制Controller和Service。
MP总结
优点
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
缺点
- 项目引入第三方包,未来升级存在一定的兼容性问题。
- 社区相对新生-文档缺乏相关的信息,或者更新不及时。
使用建议
- 任何框架或技术都有利有弊,看的角度和结合团队实际情况。
- 高内聚-低解耦肯定是软件设计思想必须要遵守的原则,所以业务代码可以适当使用MybatisPlus好的功能。
- 好用的:CRUD、自动生成工具、分页查询。
- 有点耦合但也不错的功能: 逻辑删除、乐观锁等
- AR则不怎么建议使用
- 偏业务型项目、管理后端项目等推荐使用,和jpa类似。
![微信公众号二维码](https://images.cnblogs.com/cnblogs_com/aeolian/1679458/o_wechat_gzh_qrcode.jpg)