MyBatis-Plus官网地址:https://mp.baomidou.com/
一、mybatis-plus简介:
Mybatis-Plus(简称MP)是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生。这是官方给的定义,关于mybatis-plus的更多介绍及特性,可以参考mybatis-plus官网。那么它是怎么增强的呢?其实就是它已经封装好了一些crud方法,我们不需要再写xml了,直接调用这些方法就行,就类似于JPA。
二、mybatis-plus特性:
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
- 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
三、MyBatis-Plus VS JPA
MyBatis-Plus优势:
- SQL语句可以自由控制,更灵活,性能较高
- SQL于代码分离,易于阅读和维护
- 提供XML标签,支持编写动态SQL语句
JPA优势:
- JPA移植性比较好
- 提供了很多 CRUD方法、开发效率高
- 对象化程度更高
MyBatis-Plus劣势:
- 简单的CURD都要写SQL
- XML中有大量的SQL要维护
- MyBatis自身功能很有限,但支持PLlugin
四、常用注解
- @TableName:对数据表名注解
- @TableId:表主键标识
- @TableId(value = “id”, type = IdType.AUTO):自增
- @TableId(value = “id”, type = IdType.ID_WORKER_STR):分布式全局唯一ID字符串类型
- @TableId(value = “id”, type = IdType.INPUT):自行输入
- @TableId(value = “id”, type = IdType.ID_WORKER):分布式全局唯一ID 长整型类型
- @TableId(value = “id”, type = IdType.UUID):32位UUID字符串
- @TableId(value = “id”, type = IdType.NONE):无状态
- @TableField:表字段标识
- @TableField(exist = false):表示该属性不为数据库表字段,但又是必须使用的。
- @TableField(exist = true):表示该属性为数据库表字段。
- @TableField(condition = SqlCondition.LIKE):表示该属性可以模糊搜索。
- @TableField(fill = FieldFill.INSERT):注解填充字段 ,生成器策略部分也可以配置!
- @Version:乐观锁注解、标记
- @EnumValue:通枚举类注解
- @TableLogic:表字段逻辑处理注解(逻辑删除)
- @SqlParser:租户注解
- @KeySequence:序列主键策略
五、普通查询
增:
@Autowired
private RentDetailMapper rentDetailMapper;
@Override
public void insert(String userId, String dealerId, String strategyId) {
RentDetail rentDetail=new RentDetail();
//插入
rentDetail.setUserId(userId);
rentDetail.setDealerId(dealerId);
rentDetail.setStrategyId(strategyId);
rentDetailMapper.insert(rentDetail);
}
删:
@Autowired
private RentDetailMapper rentDetailMapper;
@Override
public void delete(String Id) {
//删除
rentDetailMapper.deleteById(Id);
}
改:
@Autowired
private RentDetailMapper rentDetailMapper;
@Override
public void update(String userId, String dealerId, String strategyId) {
RentDetail rentDetail=new RentDetail();
//更新
rentDetail.setUserId(userId);
rentDetail.setDealerId(dealerId);
rentDetail.setStrategyId(strategyId);
rentDetailMapper.updateById(rentDetail);
}
查:
@Autowired
private RentDetailMapper rentDetailMapper;
@Override
public void select(String Id) {
//查找
rentDetailMapper.selectById(Id);
}
六、自定义SQL查询
接口示例:
@Mapper
@Repository
public interface IUserDao extends BaseMapper<User> {
/**
* 根据电话查找id、昵称
* @param mobile
* @param sourceId
* @return
*/
List<UserMobileVO> findId(@Param("mobile")String mobile,@Param("sourceId")String sourceId);
}
xml示例:
ps:MyBatisPlus是有驼峰命名的,不需要一个一个字段进行映射
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.netx.web.dao.IUserDao">
<select id="findId" resultType="com.netx.web.vo.UserMobileVO" >
SELECT
id,
mobile,
real_name
FROM
`user`
WHERE
mobile like '%${mobile}%'and
deleted = 0
and register_source=#{sourceId}
</select>
</mapper>
动态SQL示例:
PS:若是排序的动态查询需要注意不用#{字段名}而是用${字段名}
<select id="pageStrategy" resultType="com.app.entity.Strategy">
select * from strategy
<where>
<!--若传入的参数为空,则不做对应的筛选-->
<if test="search.house != null and search.house != ''">
house = #{search.house}
</if>
<if test="search.currncy != null and search.currncy != ''">
and currncy = #{search.currncy}
</if>
and deleted = 0 order by
<choose>
<!--若某一参数不为空,则做对应的排序(这里要前端传desc或asc来做降升序控制)-->
<when test="search.yiedlRate != null and search.yiedlRate != ''">
yiedl_rate ${search.yiedlRate}
</when>
<when test="search.winRate != null and search.winRate != ''">
win_rate ${search.winRate}
</when>
<when test="search.totalRentedCount != null and search.totalRentedCount != ''">
total_rented_count ${search.totalRentedCount}
</when>
<otherwise>
create_time desc
</otherwise>
</choose>
</where>
</select>
七、条件构造器
更多详细用法尽在官方文档:https://mp.baomidou.com/guide/wrapper.html#select
查:
/**
* 条件构造器 查询操作
* 年龄在 18~50 之间性别为男且姓名为 xx 的所有用户
*SELECT id AS id,last_name AS lastName,email,gender,age FROM tbl_employee WHERE (age BETWEEN ? AND ? AND gender = ? AND last_name = ?)
*/
@Test
public void testSelectPage(){
Page<Employee> page=new Page<>(0,2);
EntityWrapper<Employee> entityWrapper=new EntityWrapper<>();
entityWrapper.between("age",18,50).eq("gender",1).eq("last_name","Tom");
List<Employee> list = employeeMapper.selectPage(page, entityWrapper);
System.out.println(list);
}
删:
/**
* 条件构造器 删除操作
*删除名字为Tom并且性别为女年龄为45
*DELETE FROM tbl_employee WHERE (last_name = ? AND gender = ? AND age = ?)
*/
@Test
public void testDelete(){
EntityWrapper<Employee> entityWrapper=new EntityWrapper<>();
entityWrapper.eq("last_name","Tom").eq("gender",0).eq("age",45);
Integer row = employeeMapper.delete(entityWrapper);
System.out.println(row);
}
改:
/**
* 条件构造器 修改操作
*名字为xiaohong并且性别为女年龄为10的人名字改为honghonglaoshi,邮箱改为120@qq.com
* UPDATE tbl_employee SET last_name=?, email=? WHERE (last_name = ? AND gender = ? AND age = ?)
*/
@Test
public void testUpdate(){
Employee employee=new Employee();
employee.setLastName("honghonglaoshi");
employee.setEmail("120@qq.com");
EntityWrapper<Employee> entityWrapper=new EntityWrapper<>();
entityWrapper.eq("last_name","xiaohong").eq("gender",0).eq("age",10);
Integer row = employeeMapper.update(employee, entityWrapper);
System.out.println(row);
}
八、分页查询
官方文档:https://mybatis.plus/guide/page.html
XML 自定义分页
public interface UserMapper {//可以继承或者不继承BaseMapper
/**
* <p>
* 查询 : 根据state状态查询用户列表,分页显示
* </p>
*
* @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位(你可以继承Page实现自己的分页对象)
* @param state 状态
* @return 分页对象
*/
IPage<User> selectPageVo(Page<?> page, Integer state);
}
- UserMapper.xml 等同于编写一个普通 list 查询,mybatis-plus 自动替你分页
<select id="selectPageVo" resultType="com.baomidou.cloud.entity.UserVo">
SELECT id,name FROM user WHERE state=#{state}
</select>
- UserServiceImpl.java 调用分页方法
public IPage<User> selectUserPage(Page<User> page, Integer state) {
// 不进行 count sql 优化,解决 MP 无法自动优化 SQL 问题,这时候你需要自己查询 count 部分
// page.setOptimizeCountSql(false);
// 当 total 为小于 0 或者设置 setSearchCount(false) 分页插件不会进行 count 查询
// 要点!! 分页返回的对象与传入的对象是同一个
return userMapper.selectPageVo(page, state);
}
九、AR策略 (Active Record活动记录)
- Active Record(活动记录),简称AR,是一种领域模型模式,特点就是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一条记录;
参考文章:https://blog.csdn.net/xiaofeivip_top/article/details/94871238
开启AR模式的方法很简单,就是让我们的实体类继承Model类,并实现其抽象方法,指定主键即可,如下:
@Data
public class Employee extends Model<Employee> {
@TableId(value = "id",type = IdType.AUTO)
private Integer id;
@TableField
private String lastName;
private String email;
private Integer gender;
private Integer age;
/**
* 通过exit设置当前字段不存在数据库里面
*/
@TableField(exist = false)
private Double salary;
/**
* 指定当前实体类的 主键属性
* @return
*/
@Override
protected Serializable pkVal() {
return id;
}
}
测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootMybatisplusARTests {
/**
* 添加
*/
@Test
public void insertAR() {
Employee employee = new Employee();
employee.setLastName("AR");
employee.setEmail("ar@xiaofei.com");
employee.setGender(1);
employee.setAge(22);
boolean insert = employee.insert();
System.err.println(insert);
System.err.println(employee.getId());
}
/**
* 修改
*/
@Test
public void updateAR() {
Employee employee = new Employee();
employee.setId(10);
employee.setGender(0);
employee.setAge(0);
boolean b = employee.updateById();
System.err.println(b);
}
/**
* 查询
*/
@Test
public void selectAR() {
// 根据Id查询
Employee employee = new Employee();
Employee employee1 = employee.selectById(1);
// System.err.println(employee1);
// 查询全部
List<Employee> employeesAll = employee.selectAll();
// System.err.println(employeesAll);
// 查询名字带有M的
List<Employee> employees = employee.selectList(new EntityWrapper().like("last_name", "M"));
// System.err.println(employees);
// 查询总数量
int count = employee.selectCount(null);
// System.err.println(count);
// 分页
Page<Employee> page = employee.selectPage(
new Page<Employee>(1, 2), null);
System.err.println(page);
/**
* Page:{ [Pagination { total=0 ,size=2 ,pages=0 ,current=1 }], records-size:2 }
*/
List<Employee> emps = page.getRecords();
System.err.println("数据:" + emps);
}
/**
* 删除
* <p>
* 注意:删除不存在的数据在逻辑上也是成功的;
*/
@Test
public void deleteAR() {
Employee employee = new Employee();
boolean b = employee.deleteById(10);
System.err.println(b);
}
}
注意点:删除不存在的数据在逻辑上也是成功的;
十、基本配置
官方文档:https://mp.baomidou.com/config/#基本配置
使用方式:
Spring Boot:
mybatis-plus:
......
configuration:
......
global-config:
......
db-config:
......
Configuration
mapUnderscoreToCamelCase
- 类型:
boolean
- 默认值:
true
是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射。
注意
此属性在 MyBatis 中原默认值为 false,在 MyBatis-Plus 中,此属性也将用于生成最终的 SQL 的 select body
如果您的数据库命名符合规则无需使用@TableField
注解指定数据库字段名
#defaultEnumTypeHandler
- 类型:
Class<? extends TypeHandler
- 默认值:
org.apache.ibatis.type.EnumTypeHandler
默认枚举处理类,如果配置了该属性,枚举将统一使用指定处理器进行处理
- org.apache.ibatis.type.EnumTypeHandler : 存储枚举的名称
- org.apache.ibatis.type.EnumOrdinalTypeHandler : 存储枚举的索引
- com.baomidou.mybatisplus.extension.handlers.MybatisEnumTypeHandler : 枚举类需要实现IEnum接口或字段标记@EnumValue注解.(3.1.2以下版本为EnumTypeHandler)
其他就不一一列举,有兴趣可以在官方文档查阅