一、mybatis-plus
1. 什么是mybatis-plus
升级版的mybatis,目的是让mybatis更易于使用, 用官方的话说“为简化而生”
官方网址:mybatis plus
2. 初体验
(1)新建springboot项目
?(2)运行官网复制建表语句
sql语句:
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
(3)导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
(4)配置
在?application.yml ?配置文件中添加 H2 数据库的相关配置:
server:
port: 8080
spring:
application:
name: MyBatisPlus
datasource:
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/plus?userSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true
logging:
level:
com.example.plus.mapper: debug
3、Java8代解析
代码生成器(新)
(1)、mybatis plus生成配置文件
(2)、导入依赖
当前包未传递依赖 MP 包,需要自己引入!
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>
(3)、新建自动生成器MysqlGenerator
①、新建generator软件包,在建MysqlGenerator类
package com.mwy.plus.generator;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import lombok.extern.slf4j.Slf4j;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Slf4j
public class MysqlGenerator {
/**
* 数据源配置(修改成MySQL)
*/
protected static String URL = "jdbc:mysql://localhost:3306/plus?userSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true";
protected static String USERNAME = "root";
protected static String PASSWORD = "123456";
protected static DataSourceConfig.Builder DATA_SOURCE_CONFIG = new DataSourceConfig.Builder(URL, USERNAME, PASSWORD);
// 处理 all 情况
/**
* 交互式的生成器(all)
* @param tables
* @return
*/
protected static List<String> getTables(String tables) {
return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
}
public static void main(String[] args) {
FastAutoGenerator.create(DATA_SOURCE_CONFIG)
// 全局配置
.globalConfig((scanner,builder) ->
// builder就是globalConfig的构建器
builder.fileOverride() //覆盖已生成文件
.outputDir(System.getProperty("user.dir")+"\\src\\main\\java")
.author(scanner.apply("请输入你的用户名"))
.enableSwagger()
.commentDate("yyyy-MM-dd")
.build() //构建器开始工作
)
// 包配置
.packageConfig(builder-> {
builder
.parent("com.mwy.plus")
.entity("pojo")
.service("service")
.serviceImpl("service.impl")
.mapper("mapper")
.xml("mapper.xml")
.controller("controller")
.pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "\\src\\main\\resources\\mapper"))
.build();
})
// 注入配置
.injectionConfig((builder) ->
builder.beforeOutputFile(
(a, b) -> log.warn("tableInfo: " + a.getEntityName())
)
)
// 策略配置
.strategyConfig((scanner, builder) ->
builder.addInclude(getTables(scanner.apply("请输入表名,多个英文逗号分隔?所有输入 all")))
.addTablePrefix("tb_")
.entityBuilder()
.enableChainModel()
.enableLombok()
.enableTableFieldAnnotation()
.addTableFills(
new Column("create_time", FieldFill.INSERT)
)
.controllerBuilder()
.enableRestStyle()
.enableHyphenStyle()
.build())
.templateEngine(new FreemarkerTemplateEngine())
.execute();
}
}
生成成功:
学习网址:代码生成器配置新 | MyBatis-Plus
4、主键生成策略
?· 雪花算法,默认的主键生策略,如果需要保存的实体对象中没有指定的主键值,则默认使用雪? ? ? ?花算法来生成
?· 自增
ID
? ? · 数据库的字段必须是配置了自增
? ? · 对应的实体的主键字段加入自增注解:
@TableId(type = IdType.AUTO)
?· 其他类型:
AUTO:自动增长
NONE:未设置主键 ?
INPUT:手动输入
ASSIGN_ID:雪花算法
ASSIGN_UUID:排除到下划线的UUID,32位长度
(1)获取UUID ,没有规律,每一次运行的结果都不相同,用做全局ID
(2)雪花ID,用做全局ID,有规律
?5. 更新
(1)通过主键更新
package com.mwy.plus;
import com.mwy.plus.mapper.UserMapper;
import com.mwy.plus.pojo.User;
import com.mwy.plus.service.IUserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.UUID;
@SpringBootTest
class MyBatisPlusApplicationTests {
@Autowired
private UserMapper mapper;
@Autowired
private IUserService service;
@Test
void contextLoads() {
User a = new User().setId(1L).setName("bbb");
// int i = mapper.updateById(a);
boolean b = service.updateById(a);
System.out.println(b);
}
}
6. 自动填充
mybatis-plus来帮我们进行自动维护在数据表的设计中,经常需要加一些字段,如:创建时间,最后修改时间等,此时可以使用
(1)在自动填充有两种方式:
①、通过数据库完成自动填充
?②、实体类
package com.mwy.plus.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
*
* @author mwy
* @since 2022-03-14
*/
@Data
@Accessors(chain = true)
@TableName("user")
@ApiModel(value = "User对象", description = "")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("主键ID")
@TableId(value = "id",type = IdType.AUTO)
private Long id;
@ApiModelProperty("姓名")
@TableField("name")
private String name;
@ApiModelProperty("年龄")
@TableField("age")
private Integer age;
@ApiModelProperty("邮箱")
@TableField("email")
private String email;
//在代码中同步加入创建时间和最后修改时间的维护
private Date createTime;
private Date lastModifiedTime;
}
完成后可以通过新增或更新?
③、使用程序完成自动填充
将数据库中的自动维护功能取消:
?第一步:实体类中加入注解?
//在代码中同步加入创建时间和最后修改时间的维护
//表明在插入时自动维护字段
@TableField(fill = FieldFill.INSERT)
private Date createTime;
//表明在插入和更新时自动维护字段
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date lastModifiedTime;
第二步:编写处理类
// 不要忘了处理器是spring的组件
@Component
public class AutoFillHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(), metaObject);
this.setFieldValByName("lastModifiedTime",new Date(), metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
//this.setFieldValByName("createTime",new Date(), metaObject);
this.setFieldValByName("lastModifiedTime",new Date(), metaObject);
}
}
完成后可以通过新增或更新
7. 乐观锁
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式(来自官方文档):
? 取出记录时,获取当前version
? 更新时,带上这个version
? 执行更新时, set version = newVersion where version = oldVersion
? 如果version不对,就更新失败
(1)配置示例:
①、在数据库表中增加version字段,表示数据版本号,设置默认值为0
?
②、修改实体类,在使用类中加入对应的version字段,并使用是乐观锁:
//乐观锁
@TableField("version")
@Version
private int version;
③、配置乐观锁
新建configurator软件包,在建MybatisPlusConfig类
package com.mwy.plus.configurator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
④、测试
package com.mwy.plus;
import com.mwy.plus.mapper.UserMapper;
import com.mwy.plus.pojo.User;
import com.mwy.plus.service.IUserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.UUID;
@SpringBootTest
class MyBatisPlusApplicationTests {
@Autowired
private UserMapper mapper;
@Autowired
private IUserService service;
@Test
void contextLoads() {
User u1=mapper.selectById(1L);
User u2=mapper.selectById(1L);
u1.setName("mwy");
u2.setName("mi");
int i1=mapper.updateById(u1);
int i2=mapper.updateById(u2);
System.out.println(i1+"-----"+i2);
}
}
第一次修改成功,第二次未被修改:
?
?8. 条件查询
(1)
批量查询多个对象
System.out.println(mapper.selectBatchIds(Arrays.asList(2L,3L,4L)));
package com.mwy.plus;
import com.mwy.plus.mapper.UserMapper;
import com.mwy.plus.pojo.User;
import com.mwy.plus.service.IUserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.*;
@SpringBootTest
class MyBatisPlusApplicationTests {
@Autowired
private UserMapper mapper;
@Autowired
private IUserService service;
@Test
void contextLoads() {
//使用map进行查询
Map<String, Object> map = new HashMap<>();
map.put("name", "Tom");
map.put("age", 28);
List<User> users = mapper.selectByMap(map);
users.forEach(t-> System.out.println(t));
}
}
9. 分页查询
(1)、分页配置
①、在配置器MybatisPlusConfig中加入配置拦截器:
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
②、测试
package com.mwy.plus;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mwy.plus.mapper.UserMapper;
import com.mwy.plus.pojo.User;
import com.mwy.plus.service.IUserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.*;
@SpringBootTest
class MyBatisPlusApplicationTests {
@Autowired
private UserMapper mapper;
@Autowired
private IUserService service;
@Test
void contextLoads() {
mapper
.selectPage(Page.of(1l,2L),null)
.getRecords()
.forEach(System.out::println);
}
}
10. 逻辑删除
物理删除使用起来比较简单,仿照查询功能即可,不再赘述。
什么是逻辑删除?
即:标记删除,并不是真的从数据库中删除,而是做个删除标记,在查询时,过滤掉标记为删除的记录即可。
(1)数据库表结构调整
①、增加字段
?②、修改实体类
//标记该字段为逻辑删除字段
@TableLogic
private int deleted;
③、在application.yml中加入如下配置
mybatis-plus:
global-config:
db-config:
#逻辑删除字段名
logic-delete-field: deleted
# 1表示逻辑删除
logic-delete-value: 1
# 0 表示未删除
logic-not-delete-value: 0
?④、测试:
mapper.deleteById(2L);
状态发生改变:
11. Wrapper
用于构造查询条件
QueryWrapper与updateWrapper的区别:
updateWrapper还可以设置修改的值
(1)测试
@Test
void contextLoads() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
// likeRight查询右边以T开头的,likeLeft以T结尾的
wrapper.likeRight("name", "T")
.eq("age", 28);
// lt代表<,gt代表>,le代表<=
}
@Test
public void testUpdateWrapper() {
UpdateWrapper u = new UpdateWrapper();
//u.set("name", "TT");
u.eq(true, "id", 6L);
User user = userMapper.selectById(6L);
//user = new User();
user.setName("TTT");
userMapper.update(user, u);
}
结束!!!?
|