一.什么是mybatis-plus?
mybatis-plus就是mybatis的增强版,在mybatis的基础上只做增强,不做改变。对于一些单表简单的sql语句,我们几乎不用写任何代码,它的内部已经为我们封装好了,简单方便,非常适合用于快速开发。
1.1 mybatis-plus的特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer2005、SQLServer 等多种数据库
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 支持关键词自动转义:支持数据库关键词(order、key......)自动转义,还可自定义关键词
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
- 内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击
二.springboot项目集成mybatis-plus
2.1 初始化springboot项目,导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
注意:导入mp的依赖以后不要再引入mybatis和mybatis-spring!避免因为版本冲突导致的问题。
2.2 在application.properties中配置数据库的连接
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false&zeroDateTimeBehavior=convertToNull
spring.datasource.username=root
spring.datasource.password=123456
2.3 使用代码自动生成工具,一键生成代码(如下)
/**
* @author lvjianyou
* @since 2020/3/15
*/
public class CodeGenerator {
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
//*************需要修改的地方1 路径改为自己项目的实际路径 **********
gc.setOutputDir("F:\\project\\cn\\hongyuan\\onlineedu_parent\\service\\service-cms" + "/src/main/java");
gc.setAuthor("吕建友");
gc.setOpen(false); //生成后是否打开资源管理器
gc.setFileOverride(false); //重新生成时文件是否覆盖
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.ID_WORKER_STR); //主键策略
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
//************ 需要修改的地方 2******************************************
dsc.setUrl("jdbc:mysql://localhost:3306/onlineedu?serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("2556");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
//************ 需要修改的地方 3 改为自己项目的实际名称******************************************
pc.setModuleName("edu"); //模块名
pc.setParent("com.ljy"); //包名
pc.setController("controller"); //需要生成的名字
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
//************ 需要修改的地方 4 ******************************************
strategy.setInclude("crm_banner"); //要生成的表名称
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}
运行后即可以生成我们项目的全部代码,立即开始开发了!
2.4 MP的常用方法
-
select("first_conlum","second_conlum"): 选择查询出具体的某几列
-
eq("colums_name","select_name"): 查询出指定列名名称的数据。 ne() :
-
orderByDesc("conlum"): 按照指定的列根据降序排序
-
ge >= gt > le <= lt <
-
last(): 在sql语句的最后拼接一条语句。如lase("limit 8") 只查询8条语句
-
between("colums","begin","end"): 查询位于该区间内的值,也可查询字符串形式的时间 如:2019-2-03
2.5 注意
如果MP提供的方法不满足要求的话就需要自己手写sql语句,而且是使用maven构建项目,那么可能需要进行以下几个操作,不然maven默认不加载xml文件!
- 在pom.xml文件中添加配置
<build>
<!--编译项目中的xml文件-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
- 在启动类上添加注解
@MapperScan("com.ljy.edu.mapper") //你自己的mapper文件夹路径
- 在配置文件中添加配置
#配置项目的xml路径
mybatis-plus.mapper-locations=classpath:com/ljy/edu/mapper/xml/*.xml
做完这三步,应该就没问题了
三. MP特性介绍
3.1 主键策略
常见的主键策略有:1.自动增长策略。2.UUID 3.使用redis实现
3.1.1 MP自带策略(默认雪花算法,生成19位值)
MP支持的主键类型有很多:
3.2 自动填充(往往是填充时间)
如果没有自动填充的话,在之前的项目中如果需要添加时间我们往往是自己new 一个时间添加进去,这样非常的不优雅,现在我们不需要自己new时间了!
3.2.1 在表中添加两个datetime类型的字段 create_time ,update_time
3.2.2 在实体类中的属性值上面添加注解
@TableField(fill= FieldFill.INSERT) //对应创建时间
@TableField(fill = FieldFill.INSERT_UPDATE) //对应修改时间
3.2.3 创建类,实现MetaObjectHandler,实现方法
代码如下:
@Component //交给spring进行管理
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入数据时进行填充
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("gmtCreate",new Date(),metaObject);
this.setFieldValByName("gmtModified",new Date(),metaObject);
}
//修改数据时进行填充
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("gmtModified",new Date(),metaObject);
}
}
以后我们就不用操心时间的问题了!
3.3 乐观锁 和 悲观锁 ( 针对于数据库操作的)
在并发(多个人同时)进行数据库操作时,很容易出现多个人同时操作一条数据,出现丢失更新(多个人操作一条数据,最后一个提交的数据把前一个人提交的数据覆盖掉)的问题,也就是脏读,幻读,不可重复读,这样肯定是不行的。
3.3.1 概念
乐观锁:乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场景,这样可以提高程序的吞吐量。
悲观锁:当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制,在修改数据之前先锁定,再修改的方式被称之为悲观并发控制【Pessimistic Concurrency Control,缩写“PCC”,又名“悲观锁”】。
3.3.2 MP实现乐观锁的方式
- 在表中添加字段 version,作为乐观锁的版本号
- 在实体类的属性上添加注解:@version
- 配置乐观锁插件
@Configuration
public class MpConfig {
//乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
这样,乐观锁的配置就完成了!
3.4 分页查询
3.4.1 配置类中配置分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
代码使用:
//创建分页对象
Page<Teacher> teacherPage = new Page<>(current,limit);
//调用page方法后会将对应的参数封装到teacherPage对象中
QueryWrapper<Teacher> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("gmt_create");
teacherService.page(teacherPage, wrapper); //调用方法后会将查询出来的所有数据封装到teacherPage中,此时里面已经有所有数据了!
long total = teacherPage.getTotal(); //获取总记录数
.....
3.5 逻辑删除
传统的物理删除: 直接在数据库中删除数据,删除以后就再也找不回来了! 逻辑删除:在数据库中新增一个字段deleted,删除数据时并不是真正的删除,而是改变deleted状态的值!
3.5.1 在表中添加一个字段 deleted,类型为tingint即可
3.5.2 在实体类对应属性上添加注解 @TableLogic
3.5.3 配置逻辑删除插件
@Bean
public ISqlInjector iSqlInjector(){
return new LogicSqlInjector();
}
我们直接测试,就可以发现现在执行删除不是直接删除数据了,而是修改了deleted的值!
总结:这是我在学习路程上的收获,编程路漫漫,希望有感兴趣的小伙伴一起探讨,一起学习,一起进步!