一、MyBatisPlus简介
1.1. 简介
- 润物无声
只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
- 效率至上
只需简单配置,即可快速进行单表 CRUD 操作,从而节省大量时间。
- 丰富功能
代码生成、自动分页、逻辑删除、自动填充等功能一应俱全。
MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。具有无侵入,损耗小,提供强大CRUD操作、支持 Lambda、内置分页插件
等特性。其内部提供了大量的默认方法供我们调用,大大简化了操作数据库的步骤。
1.2. 准备工作
1.2.1. 引入依赖
<!--起步类-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
<!--可选:德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.9</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
1.2.2. 设置常用配置
此处以mysql的配置连接为例
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://IP:端口/数据库名?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
username: 数据库用户名
password: 数据库密码
mybatis-plus:
configuration:
# 可选项:默认的enum处理器,用于处理实体类中的枚举项存入数据库时的转换
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
# sql日志输出
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
field-strategy: 0
db-config:
logic-delete-field: deleted
# 默认id生成策略:雪花算法
id-type: assign_id
1.2.3. 定义实体类
需要注意,实体类上需要添加@TableName
并指定对应的表名,id上使用@TableId
注解标记id,指定id的名字,或者额外指定id生成策略。使用@TableField
指定其他字段,可以通过赋值value属性进行映射。
如果希望某个敏感字段在查询语句时默认不被查询,则使用@TableField(select= false)
注明
如果普通字段的名字和数据库里的字段能够对应,就可以省略@TableFile注解。如果实体类中有非数据库的字段,需要使用注解@TableField(exist = false)
注明,否则可能会报错!
package link.xiaomo.user.domain.po;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.tianji.user.enums.UserStatus;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 用户表
*
* @author Mosfield
*/
@Data
@TableName("t_user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
/**
* 用户名
*/
private String username;
/**
* 手机号
*/
@TableField("cell_phone")
private String cellPhone;
/**
* 密码
*/
private String password;
/**
* 账户状态:0-禁用,1-正常
*/
private UserStatus status;
/**
* 创建时间
*/
@TableField("create_time")
private LocalDateTime createTime;
/**
* 更新时间
*/
@TableField("update_time")
private LocalDateTime updateTime;
/**
* 创建者id
*/
private Long creator;
/**
* 修改者id
*/
private Long updater;
/**
* 权限列表,非数据库字段
*/
@TableField(exist = false)
private List<Role> roleList;
}
1.2.4. 定义mapper
需要继承BaseMapper,泛型为具体的实体类
package link.xiaomo.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import link.xiaomo.user.domain.po.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserDao extends BaseMapper<User> {
}
1.2.5. 定义Service
可以通过继承ServiceImpl,继承很多默认实现的方法。需要注意根据实体类填写对应的泛型
。
另外,继承ServiceImpl不是必须的
,目的是使用默认方法,请按需添加
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
........
}
1.2.6. 配置分页插件
package link.xiaomo.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
//1 创建MybatisPlusInterceptor拦截器对象
MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
//2 添加分页拦截器
mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mpInterceptor;
}
}
二、标准数据层开发
2.1. Mapper常用api
在service层,通过调用对应实体类的Mapper接口,可以调用如下从BaseMapper继承的通用方法。
功能 | api |
---|---|
新增 | int insert(T t) |
删除 | int deleteById(Serializable id) |
修改 | int updateById(T t) |
根据id查询 | T selectById(Serializable id) |
查询全部 | List |
分页查询 | IPage |
按条件查询 | IPage |
同时,如果你的service继承了ServiceImpl,那也可以通过 this.方法名
的方式,使用ServiceImpl提供的默认方法。但是这些默认方法和mapper提供的方法,方法名可能不同,需要注意。
2.2. 分页功能
请务必务必务必完成
步骤1.2.6
的分页配置
// 普通查询条件
QueryWrapper<User> queryWrappe = new QueryWrapper<>();
queryWrappe.eq("groupId", 18);
//1 创建IPage分页对象,设置分页参数
IPage<User> page=new Page<>(1,3);
//2 执行分页查询
userDao.selectPage(page,queryWrappe);
//3 获取分页结果
System.out.println("当前页码值:"+page.getCurrent());
System.out.println("每页显示数:"+page.getSize());
System.out.println("总页数:"+page.getPages());
System.out.println("总条数:"+page.getTotal());
System.out.println("当前页数据:"+page.getRecords());
三、条件查询方式
3.1 条件查询
普通条件查询
//方式一:按条件查询
QueryWrapper<User> qw=new QueryWrapper<>();
qw.lt("age", 18);
List<User> userList = userDao.selectList(qw);
System.out.println(userList);
lambda格式按条件查询
//方式二:lambda格式按条件查询
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.lt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
3.2 组合条件
- and条件
//并且关系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//并且关系:10到30岁之间
lqw.lt(User::getAge, 30).gt(User::getAge, 10);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
- or条件
//或者关系
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//或者关系:小于10岁或者大于30岁
lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
- NULL值处理
在多数的QueryWrapper中,如果第一个参数是boolean类型,说明如果第一个参数为true时,才会把这个查询条件加到最终的查询中。如果为false,则相当于没有这个查询条件。
Integer minAge=10; //将来有用户传递进来,此处简化成直接定义变量了
Integer maxAge=null; //将来有用户传递进来,此处简化成直接定义变量了
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//参数1:如果表达式为true,那么查询才使用该条件
lqw.gt(minAge!=null,User::getAge, minAge);
lqw.lt(maxAge!=null,User::getAge, maxAge);
List<User> userList = userDao.selectList(lqw);
userList.forEach(System.out::println);
- 链式编程
Integer minAge=10; //将来有用户传递进来,此处简化成直接定义变量了
Integer maxAge=null; //将来有用户传递进来,此处简化成直接定义变量了
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//参数1:如果表达式为true,那么查询才使用该条件
lqw.gt(minAge!=null,User::getAge, minAge)
.lt(maxAge!=null,User::getAge, maxAge);
List<User> userList = userDao.selectList(lqw);
userList.forEach(System.out::println);
四、查询投影
4.1. 只查询部分属性
如果只查询结果中的部分属性,使用如下方法
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.select(User::getId, User::getName, User::getAge);
List<User> userList = userDao.selectList(lqw);
或
QueryWrapper<User> lqw = new QueryWrapper<User>();
lqw.select("id", "name", "age", "tel");
List<User> userList = userDao.selectList(lqw);
4.2. 查询未定义的属性
QueryWrapper<User> lqw = new QueryWrapper<User>();
lqw.select("count(*) as count, tel");
lqw.groupBy("tel");
List<Map<String, Object>> userList = userDao.selectMaps(lqw);
System.out.println(userList);
投影查询如果用到了自定义结果,则结果不适合用目标对象结果。可以用map接受,也可以根据结果定义一个DTO对象进行接受
这时候其实更建议使用在xml中自定义sql
五、其他设置
5.1. id生成策略
5.1.1. id生成策略控制
-
名称:@TableId
-
类型:属性注解
-
位置:模型类中用于表示主键的属性定义上方
-
作用:设置当前类中主键属性的生成策略
-
主键生成策略:通过
type属性
设置主键属性的生成策略,值参照IdType枚举值- AUTO 使用数据库的策略
- NONE 不设置id生成策略
- INPUT 用户手工输入id
- ASSIGN_ID 雪花算法生成id
- ASSIGN_UUID uuid生成id
5.1.2. 全局策略配置
设定全局策略以后,如果不设置id策略,就按全局策略走,单独设置的话就按单独的设置来。
如果设置了表名前缀,并且不指名表名的话,就按前缀+实体类名当做表名
mybatis-plus:
global-config:
db-config:
# 全局id生成策略
id-type: assign_id
# 全局表名前缀
table-prefix: tbl_
5.2. 批量Delete/Select
5.2.1 按照主键删除多条记录
//删除指定多条数据
List<Long> list = new ArrayList<>();
list.add(1402551342481838081L);
list.add(1402553134049501186L);
list.add(1402553619611430913L);
userDao.deleteBatchIds(list);
5.2.2 根据主键查询多条记录
//查询指定多条数据
List<Long> list = new ArrayList<>();
list.add(1L);
list.add(3L);
list.add(4L);
userDao.selectBatchIds(list);
Comments NOTHING