本人是一名物联网工程专业的学生,写博客即是为了记录自己的学习历程,又希望能够帮助到很多和自己一样处于起步阶段的萌新。
临渊羡鱼,不如退而结网。一起加油!
博客主页:https://blog.csdn.net/qq_44895397
MyBatisPlus简介
一、简介
MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
二、特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 注入攻击
MyBatisPlus入门
一、使用 Spring Initializr 快速初始化一个 Spring Boot 工程
二、添加依赖
mybatis-plus-boot-starter、MySQL依赖:
<!--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>
三、配置
在 application.properties 配置文件中添加 MySQL 数据库的相关配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=yky
四、代码编写
1、mapper继承BaseMapper接口
@Mapper
public interface StudentMapper extends BaseMapper<tStudent> {
}
2、实体类
注意数据库表名和实体类名称的关系:
3、启动类
五、配置日志
控制台输出sql语句:
核心配置文件配置
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
六、测试
@SpringBootTest
public class Mybatisplusdemo01ApplicationTests {
@Autowired
private StudentMapper studentMapper;
@Test
void contextLoads() {
List<tStudent> students = studentMapper.selectList(null);
for (tStudent s : students) {
System.out.println(s);
}
}
}
MyBatisPlus的CRUD 接口
一、insert
1、插入操作
直接调用BaseMapper接口中的方法即可
//插入操作
@Test
public void add(){
tStudent student = new tStudent();
student.setName("爱敲代码的小游子");
student.setAge(19);
studentMapper.insert(student);
}
2、主键策略
(1)ID_WORKER
MyBatis-Plus默认的主键策略是:ID_WORKER
全局唯一ID
(2)自增策略
- 要想主键自增需要配置如下主键策略
- 需要在创建数据表的时候设置主键自增
- 实体字段中配置
@TableId(type = IdType.AUTO)
@TableId(type = IdType.AUTO)
private Integer id;
- 要想影响所有实体的配置,可以设置全局主键配置
#全局设置主键生成策略
mybatis-plus.global-config.db-config.id-type=auto
- 其它主键策略:
二、update
1、根据Id更新操作
@Test
public void updateStudent() {
tStudent student = new tStudent();
student.setId(1009);
student.setName("东方不败");
studentMapper.updateById(student);
}
2、自动填充
(1)数据库表中添加自动填充字段
(2)实体上添加注解
//自动填充
@TableField(fill = FieldFill.INSERT)
private Date create_time;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date update_time;
(3)实现元对象处理器接口
注意:不要忘记添加 @Component 注解
@Component
public class MyMateObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("update_time",new Date(),metaObject);
this.setFieldValByName("create_time",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("update_time",new Date(),metaObject);
}
}
注意事项
- 字段必须声明
TableField
注解,属性fill
选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段 - 填充处理器
MyMetaObjectHandler
在 Spring Boot 中需要声明@Component
或@Bean
注入 - 要想根据注解FieldFill.xxx和字段名以及字段类型来区分必须使用父类的strictInsertFill或者strictUpdateFill方法
- 不需要根据任何来区分可以使用父类的fillStrategy方法
3、乐观锁
主要解决:丢失更新,也就是说实现线程安全的数据更新
1、乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
2、配置步骤:
- 插件配置
/**
* 乐观锁插件
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
- 在实体类中的version属性添加@Version注解
//乐观锁
@TableField(fill = FieldFill.INSERT)
@Version
private Integer version;
3、特别说明
- 支持的数据类型只有 int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下 newVersion = oldVersion + 1
- newVersion 会回写到 entity 中
- 仅支持 updateById(id) 与 update(entity, wrapper) 方法
- 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
三、select
1、根据id查询记录
@Test
void selecttStudentById() {
tStudent students = studentMapper.selectById(1004);
System.out.println(students);
}
2、通过多个id批量查询
@Test
void selecttStudentById() {
List<tStudent> tStudents = studentMapper.selectBatchIds(Arrays.asList(1001, 1002, 1003));
System.out.println(tStudents );
}
3、简单的条件查询
通过map封装查询条件
- 注意:map中的key对应的是数据库中的列名。
@Test
public void testSelectByMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name", "爱敲代码的小游子");
map.put("age", 19);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
4、分页查询
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
配置类中添加分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
分页插件的使用
1、创建page对象
//创建page对象
//两个参数:当前页和每页显示记录数
Page<tStudent> studentPage = new Page<>(1,3);
2、通过调用分页查询的方法
@Test
public void pageHander(){
//创建page对象
//两个参数:当前页和每页显示记录数
Page<tStudent> studentPage = new Page<>(1,3);
//调用分页查询方法
//分页查询过程中,把分页所有的数据封装到page对象里面
studentMapper.selectPage(studentPage,null);
studentPage.getCurrent();//当前页
studentPage.getRecords();//每页数据的list集合
studentPage.getSize();//每页显示记录数
studentPage.getTotal();//总记录数
studentPage.getPages();//总页数
System.out.println(studentPage.getPages());
studentPage.hasNext();//判断是否还有下一页
studentPage.hasPrevious();//判断是否还有上一页
}
四、delete
1、根据id删除记录
@Test
public void testDeleteById(){
int result = userMapper.deleteById(8L);
System.out.println(result);
}
2、批量删除
@Test
public void testDeleteBatchIds() {
int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10));
System.out.println(result);
}
3、简单的条件查询删除
@Test
public void testDeleteByMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name", "Helen");
map.put("age", 18);
int result = userMapper.deleteByMap(map);
System.out.println(result);
}
4、逻辑删除
- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
(1)数据库中添加 deleted字段
(2)实体类属性deleted 添加注解@TableLogic
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
(3)新增数据时自动填充deleted默认值
在数据库中增加deleted字段时设置默认值后不需要再在这里设置默认值
this.setFieldValByName("deleted",0,metaObject);
(4)application.properties 加入配置(可不配置)
##逻辑删除配置
#mybatis-plus.global-config.db-config.logic-delete-value=1
#mybatis-plus.global-config.db-config.logic-not-delete-value=0
MyBatisPlus条件构造器
了解更多可以参考官方文档:https://mp.baomidou.com/
创建QueryWrapper对象
QueryWrapper<tStudent> wrapper = new QueryWrapper<>();
1、ge、gt、le、lt、isNull、isNotNull
- ge:大于等于 >=
- gt:大于 >
- le:小于等于 <=
- lt:小于 <
- isNull:字段 IS NULL
- isNotNull:字段 IS NOT NULL
public void text(){
QueryWrapper<tStudent> wrapper = new QueryWrapper<>();
wrapper.ge("id",1004);
wrapper.le("age",50);
List<tStudent> tStudents = studentMapper.selectList(wrapper);
System.out.println(tStudents);
}
2、eq、ne
- eq:等于
- ne:不等于
eq("name", "老王")--->name = '老王'
3、between、notBetween
包含大小边界
- BETWEEN 值1 AND 值2
between("age", 18, 30)--->age between 18 and 30
4、allEq
allEq(Map<R, V> params)
allEq(Map<R, V> params, boolean null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
- 例1:
allEq({id:1,name:"老王",age:null})
—>id = 1 and name = '老王' and age is null
- 例2:
allEq({id:1,name:"老王",age:null}, false)
—>id = 1 and name = '老王'
5、last
无视优化规则直接拼接到 sql 的最后
注意事项:
- 只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用
//复杂条件查询
@Test
public void select(){
QueryWrapper<tStudent> wrapper = new QueryWrapper<>();
wrapper.last("and name = ''");
List<tStudent> tStudents = studentMapper.selectList(wrapper);
System.out.println(tStudents);
}