MyBatis-Plus
MyBatisPlus
1. 基本CRUD
1.1 BaseMapper
MyBatis-Plus中的基本CRUD在内置的BaseMapper中都已得到了实现,我们可以直接使用,接口如 下:
1 | /** |
1.2 插入
1 |
|
最终执行的结果,所获取的id为1475754982694199298
这是因为MyBatis-Plus在实现插入数据时,会默认基于雪花算法的策略生成id
1.3 删除
通过id删除记录
1
2
3
4
5
6
7
public void testDeleteById(){
//通过id删除用户信息
//DELETE FROM user WHERE id=?
int result = userMapper.deleteById(1475754982694199298L);
System.out.println("受影响行数:"+result);
}通过id批量删除记录
1
2
3
4
5
6
7
8
public void testDeleteBatchIds(){
//通过多个id批量删除
//DELETE FROM user WHERE id IN ( ? , ? , ? )
List<Long> idList = Arrays.asList(1L, 2L, 3L);
int result = userMapper.deleteBatchIds(idList);
System.out.println("受影响行数:"+result);
}通过map条件删除记录
1
2
3
4
5
6
7
8
9
10
public void testDeleteByMap(){
//根据map集合中所设置的条件删除记录
//DELETE FROM user WHERE name = ? AND age = ?
Map<String, Object> map = new HashMap<>();
map.put("age", 23);
map.put("name", "张三");
int result = userMapper.deleteByMap(map);
System.out.println("受影响行数:"+result);
}
1.4 修改
1 |
|
1.5 查询
根据id查询用户信息
1
2
3
4
5
6
7
public void testSelectById(){
//根据id查询用户信息
//SELECT id,name,age,email FROM user WHERE id=?
User user = userMapper.selectById(4L);
System.out.println(user);
}根据多个id查询多个用户信息
1
2
3
4
5
6
7
8
public void testSelectBatchIds(){
//根据多个id查询多个用户信息
//SELECT id,name,age,email FROM user WHERE id IN ( ? , ? )
List<Long> idList = Arrays.asList(4L, 5L);
List<User> list = userMapper.selectBatchIds(idList);
list.forEach(System.out::println);
}通过map条件查询用户信息
1
2
3
4
5
6
7
8
9
10
public void testSelectByMap(){
//通过map条件查询用户信息
//SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
Map<String, Object> map = new HashMap<>();
map.put("age", 22);
map.put("name", "admin");
List<User> list = userMapper.selectByMap(map);
list.forEach(System.out::println);
}查询所有数据
1
2
3
4
5
6
7
public void testSelectList(){
//查询所有用户信息
//SELECT id,name,age,email FROM user
List<User> list = userMapper.selectList(null);
list.forEach(System.out::println);
}
通过观察BaseMapper中的方法,大多方法中都有Wrapper类型的形参,此为条件构造器,可针 对于SQL语句设置不同的条件,若没有条件,则可以为该形参赋值null,即查询(删除/修改)所有数据
1.6 通用Service
说明:
- 通用的Service CRUD封装IService接口,进一步封装CRUD采用
get 查询单行``remove 删除``list 查询集合``page 分页
前缀命名方式区分Mapper层以避免混淆。 - 泛型T为任意实体对象。
- 建议如果存在自定义通用Service方法的可能,请创建自己的IBaseService继承MybatisPlus所提供的基类 。
IService
MyBatis-Plus中有一个接口 IService和其实现类 ServiceImpl,封装了常见的业务层逻辑
详情查看源码IService和ServiceImpl
创建Service接口和实现类
1
2
3
4
5/**
* UserService继承IService模板提供的基础功能
*/
public interface UserService extends IService<User> {
}1
2
3
4
5
6
7/**
* ServiceImpl实现了IService,提供了IService中基础功能的实现
* 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现
*/
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}测试查询记录数
1
2
3
4
5
6
7
private UserService userService;
public void testGetCount(){
long count = userService.count();
System.out.println("总记录数:" + count);
}
2. 常用注解
2.1 @TableName
在实体类类型上添加@TableName(“t_user”),标识实体类对应的表,即可成功执行SQL语句
也可以通过全局配置解决:
1 | mybatis-plus: |
使用MyBatis-Plus提供的全局配置,为实体类所对应的表名设置默认的前缀,那么就 不需要在每个实体类上通过@TableName标识实体类对应的表
2.2 @TableId
在实体类中uid属性上通过@TableId将其标识为主键,即可成功执行SQL语句
同样也可以通过type属性来定义主键策略:
1. IdType.ASSIGN_ID(默 认) :基于雪花算法生成id
1. IdType.AUTO :使用数据库自增策略
2.3 @TableField
当实体类中的属性名和数据库中的字段名不一致时,可以使用这个注解
2.4 @TableLogic
该注解的功能是实现逻辑删除
- 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
- 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库 中仍旧能看到此条数据记录
优点:可以进行数据恢复
注意:使用逻辑删除真正执行的SQL是update
语句
3. 条件构造器和常用接口
3.1 wrapper介绍
- Wrapper:条件构造抽象类,最顶端的父类
- AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
- QueryWrapper : 查询条件封装
- UpdateWrapper : Update 条件封装
- AbstractLambdaWrapper : 使用Lambda 语法
- LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
- LambdaUpdateWrapper : Lambda 更新封装Wrapper
- AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件
3.2 QueryWrapper
3.2.1 组装查询条件
1 |
|
3.2.2 组装排序条件
1 |
|
3.2.3 组装删除条件
1 |
|
3.2.4 条件的优先级
1 |
|
1 |
|
3.2.5 组装select子句
1 |
|
3.2.6 实现子查询
1 |
|
3.3 UpdateWrapper
1 |
|
3.4 Condition
在真正开发的过程中,组装条件是常见的功能,而这些条件数据来源于用户输入,是可选的,因 此我们在组装这些条件时,必须先判断用户是否选择了这些条件,若选择则需要组装该条件,若 没有选择则一定不能组装,以免影响SQL执行的结果
思路一
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void test08() {
//定义查询条件,有可能为null(用户未输入或未选择)
String username = null;
Integer ageBegin = 10;
Integer ageEnd = 24;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace)
构成
if(StringUtils.isNotBlank(username)){
queryWrapper.like("username","a");
}
if(ageBegin != null){
queryWrapper.ge("age", ageBegin);
}
if(ageEnd != null){
queryWrapper.le("age", ageEnd);
}
//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (age >= ? AND age <= ?)
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}思路二:
上面的实现方案没有问题,但是代码比较复杂,我们可以使用带condition参数的重载方法构建查 询条件,简化代码的编写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void test08UseCondition() {
//定义查询条件,有可能为null(用户未输入或未选择)
String username = null;
Integer ageBegin = 10;
Integer ageEnd = 24;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace) 构成
queryWrapper
.like(StringUtils.isNotBlank(username), "username", "a")
.ge(ageBegin != null, "age", ageBegin)
.le(ageEnd != null, "age", ageEnd);
//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (age >= ? AND age <= ?)
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
3.5 LambdaQueryWrapper
1 |
|
3.6 LambdaUpdateWrapper
1 |
|
4. 插件
4.1 分页插件
MyBatis Plus自带分页插件,只要简单的配置即可实现分页功能
添加配置类Config
1
2
3
4
5
6
7
8
9
10
11
//可以将主类中的注解移到此处
public class MybatisPlusConfig {
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void testPage(){
//设置分页参数
Page<User> page = new Page<>(1, 5);
userMapper.selectPage(page, null);
//获取分页数据
List<User> list = page.getRecords();
list.forEach(System.out::println);
System.out.println("当前页:"+page.getCurrent());
System.out.println("每页显示的条数:"+page.getSize());
System.out.println("总记录数:"+page.getTotal());
System.out.println("总页数:"+page.getPages());
System.out.println("是否有上一页:"+page.hasPrevious());
System.out.println("是否有下一页:"+page.hasNext());
}
4.2 xml自定义分页
UserMapper中定义接口方法
1
2
3
4
5
6
7/**
* 根据年龄查询用户列表,分页显示
* @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位
* @param age 年龄
* @return
*/
IPage<User> selectPageVo(; Page<User> page, Integer age)UserMapper.xml中编写SQL
1
2
3
4
5
6<!--SQL片段,记录基础字段-->
<sql id="BaseColumns">id,username,age,email</sql>
<!--IPage<User> selectPageVo(Page<User> page, Integer age);-->
<select id="selectPageVo" resultType="User">
SELECT <include refid="BaseColumns"></include> FROM t_user WHERE age > #{age}
</select>测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void testSelectPageVo(){
//设置分页参数
Page<User> page = new Page<>(1, 5);
userMapper.selectPageVo(page, 20);
//获取分页数据
List<User> list = page.getRecords();
list.forEach(System.out::println);
System.out.println("当前页:"+page.getCurrent());
System.out.println("每页显示的条数:"+page.getSize());
System.out.println("总记录数:"+page.getTotal());
System.out.println("总页数:"+page.getPages());
System.out.println("是否有上一页:"+page.hasPrevious());
System.out.println("是否有下一页:"+page.hasNext());
}
5. 通用枚举
表中的有些字段值是固定的,例如性别(男或女),此时我们可以使用MyBatis-Plus的通用枚举来实现
数据库表汇总添加sex字段
创建通用枚举类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;
public enum SexEnum {
MALE(1, "男"),
FEMALE(2, "女");
private Integer sex;
private String sexName;
SexEnum(Integer sex, String sexName) {
this.sex = sex;
this.sexName = sexName;
}
}配置扫描通用枚举
1
2
3
4
5
6
7
8
9
10
11
12
13mybatis-plus:
configuration:
# 配置MyBatis日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
# 配置MyBatis-Plus操作表的默认前缀
table-prefix: t_
# 配置MyBatis-Plus的主键策略
id-type: auto
# 配置扫描通用枚举
type-enums-package: com.CPG.mybatisplus.enums测试
1
2
3
4
5
6
7
8
9
10
11
public void testSexEnum(){
User user = new User();
user.setName("Enum");
user.setAge(20);
//设置性别信息为枚举项,会将@EnumValue注解所标识的属性值存储到数据库
user.setSex(SexEnum.MALE);
//INSERT INTO t_user ( username, age, sex ) VALUES ( ?, ?, ? )
//Parameters: Enum(String), 20(Integer), 1(Integer)
userMapper.insert(user);
}
6. 代码生成器
6.1 引入依赖
1 | <dependency> |
6.2 快速生成
1 | public class FastAutoGeneratorTest { |
7. 多数据源
适用于多种场景:纯粹多库、 读写分离、 一主多从、 混合模式等
目前我们就来模拟一个纯粹多库的一个场景,其他场景类似
场景说明: 我们创建两个库,分别为:mybatis_plus(以前的库不动)与mybatis_plus_1(新建),将 mybatis_plus库的product表移动到mybatis_plus_1库,这样每个库一张表,通过一个测试用例 分别获取用户数据与商品数据,如果获取到说明多库模拟成功
7.1 创建数据库及表
创建数据库mybatis_plus_1和表product
1
2
3
4
5
6
7
8
9
10
11CREATE DATABASE `mybatis_plus_1` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
use `mybatis_plus_1`;
CREATE TABLE product
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',
price INT(11) DEFAULT 0 COMMENT '价格',
version INT(11) DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id)
);添加测试数据
1
INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);
删除mybatis_plus库product表
1
2use mybatis_plus;
DROP TABLE IF EXISTS product;
7.2 引入依赖
1 | <dependency> |
7.3 配置多数据源
1 | spring: |
7.4 创建用户service
1 | public interface UserService extends IService<User> { |
1 | //指定所操作的数据源 |
7.5 创建商品service
1 | public interface ProductService extends IService<Product> { |
1 |
|
7.6 测试
1 |
|