简介
MybatisPlus概述
MyBatis Plus是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生(提供了快速使用mybatis的方式)。
MybatisPlus特点
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
开发导入相关依赖
```java 普通Maven项目下的依赖com.baomidou mybatis-plus 3.4.2
SpringBoot环境下的MP(项目中使用)
**注意:如果想在mybatis-plus看打印的sql,可在application.yml(application.properties)配置:**
```xml
#mybatis-plus配置控制台打印完整带参数SQL语句
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
MybatisPlus实现常规增删改操作
MybatisPlus实现插入操作
方法
# T为泛型
int insert(T entity);
测试代码
/*
* 要求:添加名为大宝贝的user数据
* sql语句:insert into tb_user(xx,xx,xx,...) values (xx,xx,xx,....)
* */
@Test
public void testAddUesr2ById() {
User user = User.builder()
.userName("大宝贝")
.age(38)
.name("wq")
.password("123456")
.build();
int result = userMapper.insert(user);
if (result > 0) {
System.out.println("添加成功");
}
System.out.println("user = " + user);
}
MybatisPlus主键生成策略-@TableId
注解@TableId介绍
@TableId注解作用:
1.标识实体类中主键对应属性;
2.定义主键生成策略;
@TableId使用:
添加在实体类的主键对应的成员属性上即可;
代码展示
# 此代码在User实体类中
/**
* @TableId: 指定当前表的主键
* value: 建立数据库主键字段与实体字段的对应关系
* type: 设置主键生成策略,
* 默认情况下使用雪花算法
* IdType.AUTO:使用数据库的主键自增
*/
@TableId(type = IdType.AUTO)
private Long id;
private String userName;
private String password;
MybatisPlus常用主键生成策略
生成策略 | 应用场景 | 特点 |
---|---|---|
IdType.AUTO | 数据库主键自增(确保数据库设置了 主键自增 否则无效) | 1.使用数据库自带的主键自增值; 2.数据库自增的主键值会回填到实体类中; 3.数据库服务端生成的; |
IdType.ASSIGN_ID | 主键类型为number类型或数字类型String | 1.MP客户端生成的主键值; 2.生成的主键值是数字形式的字符串 3.主键对应的类型可以是数字类型或者数字类型的字符串 4.底层基于雪花算法,让数据库的唯一标识也参与id的生成运算,保证id在分布式环境下,全局唯一(避免id的主键冲突问题); |
IdType.ASSIGN_UUID | 主键类型为 string(包含数字和字母组成) | 1.生成的主键值包含数字和字母组成的字符串; 2.注意事项:如果数据库中主键值是number类型的,可不可用 |
普通列注解-@TableField
注意:
- 通过@TableField(“表列名”) 指定映射关系,以下情况可以省略:
- 名称一样
- 数据库字段使用_分割,实体类属性名使用驼峰名称(自动开启驼峰映射)
忽略某个字段的查询和插入 @TableField(exist = false) ```java // @TableName: 指定当前对象对应的数据库表 @TableName(“tb_user”) @Data @NoArgsConstructor @AllArgsConstructor @Builder public class User {
/**
- @TableId: 指定当前表的主键
- value: 建立数据库主键字段与实体字段的对应关系
- type: 设置主键生成策略,
- IdType.NONE/ASSIGN_ID:默认情况下使用雪花算法
- IdType.AUTO:使用数据库的主键自增
- ASSIGN_UUID:使用UUID生成一个全局唯一字符串 */ @TableId(type = IdType.AUTO) private Long id; private String userName; private String password; // 建立数据库字段与实体字段的对应关系 @TableField(“与数据库字段名对应”) @TableField(“t_name”) private String name; private Integer age; // 忽略此字段 @TableField(exist = false) private String email; }
<a name="xr2M8"></a>
## MybatisPlus实现删除操作
```java
//根据entity 条件,删除记录
int delete(@Param( Constants . WRAPPER) Wrapper<T> wrapper);
//删除(根据ID批量删除)
int deleteBatchIds (@Param( Constants . COLLECTION) Collection<? extends Serializable> idList);
//根据ID删除
int deleteById(Serializable id);
//根据columnMap 条件,删除记录
int deleteByMap(@Param(Constants . COLUMN MAP) Map<String, object> columnMap);
根据ID删除
int count = userMapper.deleteById(8L);
根据ID集合批量删除
List ids = new ArrayList();
ids.add(6);
ids.add(7);
userMapper.deleteBatchIds(ids);
根据Map条件删除
Map<String, Object> map = new HashMap<>();
//delete from tb_user where user_name = ? and age = ?
map.put("user_name","itcast");
map.put("age","18");
userMapper.deleteByMap(map);
测试代码
/*
* 要求:删除id为 16 的用户
* sql语句:DELETE FROM tb_user WHERE id=?
* */
@Test
public void testDelUesrById() {
int result = userMapper.deleteById(2L);
if (result > 0) {
System.out.println("删除成功");
}
}
/*
* 要求:删除id为 15、14 的用户
* sql语句:DELETE FROM tb_user WHERE id=? or id=?
* sql语句:DELETE FROM tb_user WHERE id IN ( ? , ? )
* */
@Test
public void testDelUesrByIds() {
List<Long> list = new ArrayList<>();
list.add(14L);
list.add(15L);
int result = userMapper.deleteBatchIds(list);
if (result > 0) {
System.out.println("删除成功");
}
}
/*
* 要求:删除user_name为王八衰 age 为22 的用户
* sql语句:DELETE FROM tb_user WHERE user_name = ? AND age = ?
* */
@Test
public void testDelUesrByCondition() {
Map<String, Object> map = new HashMap<>();
map.put("user_name", "王八衰");
map.put("age", 22);
int result = userMapper.deleteByMap(map);
if (result > 0) {
System.out.println("删除成功");
}
}
MybatisPlus实现更新操作
方法介绍
//根据whereEntity条件,更新记录
int update(@Param( Constants . ENTITY) T entity, @Param(Constants .WRAPPER) Wrapper<T> updatewrapper) ;
//根据ID修改
int updateById(@Param Constants . ENTITY) T entity);
只更新对象属性中被赋值的字段
测试代码
/*
* 修改用户id为 4 的username修改为 李催
* sql语句:UPDATE tb_user SET user_name=? WHERE id=?
*/
@Test
public void testUpdate() {
User user = User.builder().id(4L).userName("李催").build();
int result = userMapper.updateById(user);
if (result > 0) {
System.out.println("更新成功");
}
}
MybatisPlus实现查询操作
//1根据ID查询
T selectById(Serializable id);
//1根据entity 条件,查询条记录
T select0ne(@Paran(Constants . MIRAPPER) Wrapper<T> queryhirapper);
//1查询(根据ID批量查询)
List<T> selectBatchIds(@Param(Constants . COLLECTION) Collection<? extends Serializable> idList);
//根据entity 条件,查询全部记录
List<T> selectList(@Param(Constants . MIRAPPER) Wrapper<T> queryWrapper);
//1查询(根据columnMap 条件)
List<T> selectByMap(@Param(Constants . COLUPN MAP) Map<String, object> columnMap);
//根据wirapper 条件,查询全部记录
List<Map<String, object>> selectMaps (@Param(Constants . WRAPPER) Wrapper<T> queryirapper);
//根据Wirapper条件,查询全部记录。注意: 只返回第一个字段的值
List<object> selectobjs(@Param(Constants .WRAPPER) irapper<T> queryhirapper);
//1根据entity 条件,查询全部记录(并页)
IPage<T> selectPage(IPage<T> page, @Param(Constants . MRAPPER) wrapper<T> querywrapper);
//1根据wrapper 条件,查询全部记录(并翻页)
IPageCMap<String, object>> selectMapsPage(IPage<T> page, @Param(Constants . MRAPPER) Hirapper<T> que
//1根据Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants .MRAPPER) wrapper<T> queryirapper);
MybatisPlus实现分页查询
配置分页查询拦截器
@Configuration
@MapperScan("com.itheima.mapper")
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
测试代码
/*
* 要求:分页查询user数据,每页5条数据,查询第一页数据
* sql语句:SELECT * FROM tb_user LIMIT 0,5
* sql语句:SELECT * FROM tb_user LIMIT 5 (简写形式)
*/
@Test
public void testPage() {
IPage<User> page = new Page<>(0, 5);
IPage<User> result = userMapper.selectPage(page, Wrappers.emptyWrapper());
System.out.println("result = " + result);
System.out.println("------------------------");
//获取分页得到的集合
List<User> records = result.getRecords();
for (User record : records) {
System.out.println(record);
}
System.out.println("------------------------");
//获取数据库中的总条数
long total = result.getTotal();
System.out.println("total = " + total);
}
QueryWrapper查询与LambdaQueryWrapper查询
Wrapper接口介绍
/**
* 基础比较查询
*
* Wrapper接口:
* 1.QueryWrapper: 查询
* LambdaQueryWrapper
* 2.UpdateWrapper: 增删改
* LambdaUpdateWrapper
*/
QueryWrapper常用API
eq( ) : 等于 =
ne( ) : 不等于 <>
gt( ) : 大于 >
ge( ) : 大于等于 >=
lt( ) : 小于 <
le( ) : 小于等于 <=
between ( ) : BETWEEN 值1 AND 值2
notBetween ( ) : NOT BETWEEN 值1 AND 值2
in( ) : in
notIn( ) :not in
//sql中反向查询eg:not like != 等等,查询时是不会走索引的;
测试代码
/*
* 要求:查询用户中姓名包含"伤",密码为"123456",且年龄为19或者25或者29,查询结果按照年龄降序排序;
* sql语句:SELECT * FROM tb_user WHERE (user_name LIKE ? AND password = ? AND age IN (?,?,?)) ORDER BY age DESC
*/
@Test
public void testConditions1Query() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("user_name", "伤")
.eq("password", "123456")
.in("age", 19, 25, 29)
.orderByDesc("age");
List<User> users = userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
/*
* 要求:查询用户中姓名包含"伤",密码为"123456",且年龄为19或者25或者29,查询结果按照年龄降序排序;
* sql语句:SELECT user_name,age FROM tb_user WHERE (user_name LIKE ? AND password = ? AND age IN (?,?,?)) ORDER BY age DESC
*/
@Test
public void testConditions2Query() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(User::getUserName, "伤")
.eq(User::getPassword, "123456")
.in(User::getAge, 19, 25, 29)
.orderByDesc(User::getAge);
List<User> users = userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
总结
- 建议使用第二种方式,这种方式是的代码更加的有维护性
- 第一种存在的原因:只有java jdk8以上的版本才支持第二种写法
QueryWrapper逻辑查询or
OR查询说明
1.通过QueryWrapper多条件查询时,默认使用and关键字拼接SQL; 2.通过QueryWrapper调用or()方法时,底层会使用or关键字拼接方法左右的查询条件;
测试代码
/* * 要求:查询用户密码为"123456",或者 age 为 20、21、22,并且要求每页显示5条,查询第二页的数 据; * sql语句:SELECT user_name,age FROM tb_user WHERE password = ? or age IN (?,?,?) */ @Test public void testConditionsOrQuery() { IPage<User> userPage = new Page<>(2, 5); LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(User::getPassword, "123456") .or() .in(User::getAge, 20, 21, 22); IPage<User> userIPage = userMapper.selectPage(userPage, wrapper); List<User> records = userIPage.getRecords(); for (User record : records) { System.out.println(record); } }
QueryWrapper模糊查询like
模糊查询常用方法
like("表列名","条件值"); 作用:查询包含关键字的信息,底层会自动添加匹配关键字,比如:%条件值% likeLeft("表列名","条件值"); 作用:左侧模糊搜索,也就是查询以指定条件值结尾的数据,比如:%条件值 likeRight("表列名","条件值");作用:右侧模糊搜索,也就是查询以指定条件值开头的数据,比如:条件值%
测试代码
/** * 模糊查询 */ @Test public void testFind3(){ QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.like("user_name","伤"); // 查询所有 //List<User> list = userMapper.selectList(null); List<User> list = userMapper.selectList(wrapper); for (User user : list) { System.out.println(user); } }
QueryWrapper排序查询
核心方法
orderByAsc 升序排序 orderByDesc 降序排序
测试代码
```java /**- 排序查询
- 先根据age升序排序,如果年龄相同则按照id降序排序
*/
@Test
public void testFind4(){
QueryWrapper
wrapper = new QueryWrapper<>(); wrapper.orderByAsc(“age”).orderByDesc(“id”); // 查询所有 //List list = userMapper.selectList(null); List list = userMapper.selectList(wrapper); for (User user : list) {
} }System.out.println(user);
<a name="aJK6E"></a>
### QueryWrapper限定字段查询
<a name="IWdvT"></a>
#### select方法说明
```java
MP查询时,默认将表中所有字段数据映射查询,但是有时我们仅仅需要查询部分字段信息,这是可以使用select()方法限定返回的字段信息,避免I/O资源的浪费;
如:wrapper.select("字段1","字段2",......)
代码测试
/**
* 指定查询字段
*/
@Test
public void testFind5(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByAsc("age").orderByDesc("id").select("id","user_name","age");
// 查询所有
//List<User> list = userMapper.selectList(null);
List<User> list = userMapper.selectList(wrapper);
for (User user : list) {
System.out.println(user);
}
}
QueryWrapper实现分页条件查询
常用方法
//参数1:分页对象
//参数2:查询条件
mapper.selectPage(page,wrapper);
测试代码
/*
* 要求:查询用户密码为"123456"的数据,并且要求每页显示5条,查询第二页的数据;
* sql语句:SELECT user_name,age FROM tb_user WHERE (user_name LIKE ? AND password = ? * AND age IN (?,?,?)) ORDER BY age DESC
*/
@Test
public void testConditionsPageQuery() {
IPage<User> userPage = new Page<>(1, 5);
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getPassword, "123456");
IPage<User> userIPage = userMapper.selectPage(userPage, wrapper);
List<User> records = userIPage.getRecords();
for (User record : records) {
System.out.println(record);
}
}
MybatisPlus实现Service封装
MybatisPlus封装Service介绍
说明
- MybatisPlus为了开发更加快捷,对业务层也进行了封装,直接提供了相关的接口和实现类;
我们在进行业务层开发时,可以继承它提供的接口和实现类,使得编码更加高效;
实现流程
定义一个服务扩展接口,该接口继承公共接口IService;
- 定义一个服务实现类,该类继承ServiceImpl
,并实现自定义的扩展接口; 核心API
MybatisPlus封装Service实现
定义服务扩展接口
//在公共接口的基础上扩展 public interface UserService extends IService<User> { }
定义服务实现
@Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}
自动填充功能
添加@TableField注解
@TableField(fill = FieldFill.INSERT) //插入数据时进行填充 private String password;
编写MyMetaObjectHandler
```java package com.itheima.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
- @author 12090
@dept 自动注入配置类 */ @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler {
@Override public void insertFill(MetaObject metaObject) {
log.info("start insert fill ...."); /** * 起始版本 3.3.3(推荐) * 注意:fieldName必须要和实体类中的属性名一致 */ this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class);
}
@Override public void updateFill(MetaObject metaObject) {
log.info("start update fill ...."); /** * 起始版本 3.3.3(推荐) */ this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class);
MybatisPlus代码生成器
开源地址:https://gitee.com/jitheima/mp_generator.git
或者使用MybatisX插件