目录
一、MyBatisPlus 概述
官网:Redirect
参考教程:http://mp.baomidou.com/guide/
MyBatis-Plus(简称 MP)是一个 Mybatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。(baomidou 组织开发)
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 物理分页,开发者无需关心具体操作,
- 主键策略实现方式
1. 自增 相对简单,不安全,效率高
2. UUID 随机算法,安全,效率低
3. 第三方工具:Redis(单线程自增 原子性)
4. MP:mybatisplus 主键策略 @TableId
1、MyBatis-Plus入门
1. xml配置文件
<groupId>com.atguigu</groupId>
<artifactId>mybatisplus</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatisplus</name>
<description>mybatisplus</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.2.1.RELEASE</spring-boot.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
数据库,实体类省略
2. 主类
@SpringBootApplication
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MyBatispPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MyBatispPlusApplication.class, args);
}
}
3. Dao层 mapper接口,通用Mapper中已经集成了简单的 CRUD 操作
@Repository //注意导包:baomidou
public interface UserMapper extends BaseMapper<User> {
}
4. 主启动类
@SpringBootApplication
@MapperScan("com.atguigu.mybatisplus.mapper")
public class MyBatispPlusApplication {
public static void main(String[] args) {
SpringApplication.run(MyBatispPlusApplication.class, args);
}
}
5. application.application.properties 配置日志
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
6. 测试类
@SpringBootTest
public class MybatisPlusApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testSelectList() {
System.out.println(("----- selectAll method test ------"));
//UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper
//所以不填写就是无任何条件
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
1. 主键策略 @TableId
MyBatis-Plus默认的主键策略是:ID_WORKER 全局唯一ID ()
参考资料:分布式系统唯一ID生成方案汇总:分布式系统唯一ID生成方案汇总 - nick hao - 博客园
1、需要在创建数据表的时候设置主键自增
2、实体字段中配置 @TableId (type = IdType.AUTO)
//主键自增,默认AUTO 数据库自增
@TableId(type = IdType.AUTO)
private Long id;
2. MP 实现自动填充 @TableField
项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
我们可以使用MyBatis Plus的自动填充功能,完成这些字段的赋值工作:
1. 实体类、数据库添加字段 @TableField 设置何时填充?
//MP自动填充:设置何时填充
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
2. 添加处理器,填充什么?实现 MetaObjectHandler接口
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//添加时执行的方法
@Override
public void insertFill(MetaObject metaObject) {
//根据字段设置值,注意为实体类属性,传入源对象
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
DEFAULT, 默认不处理
INSERT, 插入时填充字段
UPDATE, 更新时填充字段
INSERT_UPDATE,插入和更新时填充字段
(修改有问题)
3. MP 实现乐观锁
主要适用场景:当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新
使用乐观锁,需要先拿到版本号。
1. 修改实体类、表字段,MP 实现自动填充
//2.MP实现乐观锁
@Version
@TableField(fill = FieldFill.INSERT) //实现自动填充
private Integer version;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//添加时执行的方法
@Override
public void insertFill(MetaObject metaObject) {
//根据字段设置值
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
this.setFieldValByName("version",1,metaObject);
}
2. MybatisPlusConfig 中注册乐观锁插件
@Configuration
@EnableTransactionManagement //声明式事务
//@MapperScan("com.atguigu.mybatis_plus.mapper") 启动类配置类配一处就可以
public class MybatisPlusConfig {
//乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
3. 修改测试
@Test
public void testUpdateUser(){
//先查询,后修改
User user = userMapper.selectById(1546746129159331842L);
//User user = new User();
//user.setId(1546746129159331842L);
user.setName("wangwu5");
int i = userMapper.updateById(user);
System.out.println("i = " + i);
}
注意:修改操作,先查询在修改
4. select 查询操作
1、根据id查询记录
User user = userMapper.selectById(1546746129159331842L);
2、通过多个id批量查询 (了解) selectBatchIds
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
3、简单的条件查询 (了解)
通过map封装查询条件
//简单多条件查询
@Test
public void testGetByInfo(){
Map<String,Object> map =new HashMap<>();
map.put("name","testUpdate");
map.put("age",18);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
批量删除,同理
int i1 = userMapper.deleteBatchIds(Arrays.asList(4, 5));
5. 分页查询 ★
1. 添加插件
//分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
2. 查询语句
//分页查询
@Test
public void testByPage(){
//注意导包,苞米豆!
//参数:当前页,本页记录数
Page<User> page = new Page<>(1,2);
//写法1
//Page<User> userPage = userMapper.selectPage(page, null);
//写法2 数据会自动注入page对象
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println); //分页数据集合
System.out.println("当前页 = "+page.getCurrent());
System.out.println("总页数 = "+page.getPages());
System.out.println("每页记录数 = "+page.getSize());
System.out.println("总记录数 = "+page.getTotal());
System.out.println("是否有下一页 = "+page.hasNext());
System.out.println("是否有上一页 = "+page.hasPrevious());
}
6. 逻辑删除 ★
- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
1. 数据库、实体类添加 deleted字段
//3.逻辑删除软删除 value = "" 未删除的值,默认值为0,delval = "" 删除后的值,默认值为1
//@TableLogic(value = "1",delval = "0")
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
2. 元对象处理器接口添加deleted的insert默认
//添加时执行的方法
@Override
public void insertFill(MetaObject metaObject) {
//根据字段设置值
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
this.setFieldValByName("version",1,metaObject);
this.setFieldValByName("deleted",0,metaObject);
}
3. application.properties 软删除配置
注解加入属性参数,或采用默认值则不用配置
#软删除配置 1表示已删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
4. 测试
删除操作,变成了修改deleted查询操作时,会自动添加delete条件
2、Wrapper 条件构造器 ★★
Wrapper : 条件构造抽象类,最顶端父类
AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
QueryWrapper : 查询条件封装
UpdateWrapper : Update 条件封装
AbstractLambdaWrapper : 使用Lambda 语法
LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
LambdaUpdateWrapper : Lambda 更新封装Wrapper
2. 常用方法
1. eq(等于)、ne(不等)
2. ge(大于等于)、gt(小于等于)、le(大于)、lt(小于)
3. between (范围查询)
4. like (模糊查询)
5. orderByDesc (降序查询)
6. select (指定字段查询)
//Wapper 条件构造器
@Test
public void testByWrapper(){
QueryWrapper<User> wapper = new QueryWrapper<>();
//注意,此处用的是表字段,拼写SQL
//1. eq、ne
//wapper.eq("name", "baishu11");
//2.ge(大于等于)、gt、le、lt
//wapper.ge("age",3);
//3. between (前后都包括)
//wapper.between("age",5,6);
//4. like
//wapper.like("name","baishu");
//5. orderByDesc
//wapper.orderByDesc("age");
//6. select (查询指定字段)
wapper.select("name","age");
List<User> users = userMapper.selectList(wapper);
users.forEach(System.out::println);
}
Service 层 父类:
IService ServiceImpl