使用MyBatisPlus进行增删改查

代码及文档地址
官方地址: MyBatis-Plus
代码发布地址 :
        Github: https://github.com/baomidou/mybatis-plus
        Gitee: https://gitee.com/baomidou/mybatis-plus
文档发布地址 : https://baomidou.com/pages/24112f

目录

 二、基本CRUD

1.插入

2.删除

(1)deleteById()

(2)deleteBatchByIds()

(3)deleteByMap(Map var1),>

3.修改

(1)updateById()

4.查询

(1)selectById()

(2)selectBatchIds()

(3)selectByMap(Map),>

(4)selectList()

5.通用Service

三、常用注解

1.@TableId

(1)value

(2)type

2.@TableField

3.@TableLogic

四、条件构造器和常用接口

1、wapper介绍

2、QueryWrapper

(1)组转查询条件

(2)组装排序条件

(3)组装删除条件

(4)条件优先级

(5)组装select子句

(6)实现子查询

3.UpdateWrapper

4、condition

        思路一: 

        思路二:

5、LambdaQueryWrapper

6、LambdaUpdateWrapper

五、分页功能

1.分页插件

(1)配置

(2)测试 

2.xml自定义分页

(1)UserMapper中定义接口方法

(2)UserMapper.xml中编写SQL

(3)测试


 一、前期准备

1.依赖引入(springboot):

<!--    MyBatisPlus     -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

注意

引入 MyBatis-Plus 之后请不要再次引入 MyBatis 以及 MyBatis-Spring,以避免因版本差异导1.致的问题

2.application.yml配置信息

spring:
  datasource:
    # 注意MySQL驱动器的版本
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 数据库账号名
    username root
    # 密码
    password: xxxx
    url: jdbc:mysql://localhost:3306/数据库名字?characterEncoding=utf-8

mybatis-plus:
  configuration:
    # 打印SQL信息
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  # 指定mapper.xml 位置何处
  mapper-locations:
    classpath: mapper/**Mapper.xml

3. MySQL数据表中添加User表

DROP TABLE IF EXISTS user;

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)
);

DELETE FROM user;

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');

 4. 项目中添加实体类(需要注入依赖lombok)

 5.创建UserMapper.xml( resources 目录下)

<?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.example.mybatisplus.mapper.UserMapper">

</mapper>

 6.创建UserMapper接口,接口继承MyBatisPlus提供的BaseMapper<T>

7.测试 

 到这里,前期工作就做好了,我们测试一下是否成功配置好了

 到这个test目录下面创建一个selectTest类,代码如下:

// 标记为测试类
@SpringBootTest
public class selectTest {
    // 依赖注入
    @Resource
    private UserMapper userMapper;

    // 标记为测试方法
    @Test
    public void selectAll(){
        List<User> list = userMapper.selectList(null);
        list.forEach(System.out::println);
    }
}

找到左方的启动按钮

 如果是一下情况就说明成功配置好MyBatisPlus,可以正常使用了

 二、基本CRUD

BaseMapper<T> 接口所提供的方法

1.插入

insert方法

@Test
    public void insertTest(){
        // 创建user实例
        User user = new User();
        // 设置姓名
        user.setName("张三");
        // 设置年龄
        user.setAge(18);
        // 设置邮箱
        user.setEmail("adfaf@aa.com");
        // INSERT INTO user ( id, `name`, age, email ) VALUES ( ?, ?, ?, ? )
        userMapper.insert(user);
        
    }

 INSERT INTO user ( id, `name`, age, email ) VALUES ( ?, ?, ?, ? )

这条语句是insert所对应的SQL语句,这个insert方法是从BaseMapper中继承过来的

 在上面代码中,我们没有设置id值,所以在插入数据的时候,MyBatisPlus使用了默认的雪花算法,雪花算法是基于时间戳+机器ID+流水号实现的,这样以保证id尽量不存在相同的

 

2.删除

(1)deleteById()

通过id删除数据

@Test
    public void testDeleteById(){
        //通过id删除用户信息
        //DELETE FROM user WHERE id=?
        int result = userMapper.deleteById( 1628657874697723905L);
        System.out.println("受影响行数:"+result);
    }

结果: 

(2)deleteBatchByIds()

通过id列表批量删除表中数据

@Test
    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);
    }

结果:

(3)deleteByMap(Map<String, Object> var1)

这个方法是实现条件删除,使用Map来构建条件语句

@Test
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);
}

 从上面代码中,可以看到,map中所设置的就where后面的条件,map的key就是表中的字段,value就是筛选值

 结果:

3.修改

(1)updateById()

根据id值来更新数据,这个方法的参数是T, 将user传入方法中,updateById 会根据对象中的id值为条件,其他值为更新内容来进行更新数据

@Test
public void testUpdateById(){
    User user = new User(4L, "admin", 22, null);
    //UPDATE user SET name=?, age=? WHERE id=?
    int result = userMapper.updateById(user);
    System.out.println("受影响行数:"+result);
}

结果:

4.查询

(1)selectById()

根据Id查询数据

@Test
public void testSelectById(){
    //根据id查询用户信息
    //SELECT id,name,age,email FROM user WHERE id=?
    User user = userMapper.selectById(4L);
    System.out.println(user);
}

(2)selectBatchIds()

根据Id列表查询数据

@Test
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);
}

(3)selectByMap(Map<String, Object>)

根据设置条件来进行查询数据

@Test
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);
}

(4)selectList()

直接查询所有数据

@Test
public void testSelectList(){
    //查询所有用户信息
    //SELECT id,name,age,email FROM user
    List<User> list = userMapper.selectList(null);
    list.forEach(System.out::println);
}

        在这里我们可以注意到这个方法传进去的参数为null,实际上参数类型为: Wrapper,这个参数的意义是传入一个条件构造器(这个条件构造器,我们在后面会介绍),在这里,由于我们传进去的是一个null,默认为没有条件,所以就直接查询所有了

5.通用Service

  • 通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get 查询单行 remove list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆,
  • 泛型 T 为任意实体对象
  • 建议如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类
  • 官网地址:https://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%A3
        MyBatis-Plus中有一个接口 IService 和其实现类 ServiceImpl 封装了常见的业务层逻辑

/**
* UserService继承IService模板提供的基础功能
*/
public interface UserService extends IService<User> {

}
/**
* ServiceImpl实现了IService,提供了IService中基础功能的实现
* 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements
UserService {


}

测试查询记录数 

@Autowired
private UserService userService;
@Test
public void testGetCount(){
    long count = userService.count();
    System.out.println("总记录数:" + count);
}

测试批量插入

@Test
public void testSaveBatch(){
    // SQL长度有限制,海量数据插入单条SQL无法实行,
    // 因此MP将批量插入放在了通用Service中实现,而不是通用Mapper
    ArrayList<User> users = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        User user = new User();
        user.setName("ybc" + i);
        user.setAge(20 + i);
        users.add(user);
    }
    //SQL:INSERT INTO t_user ( username, age ) VALUES ( ?, ? )
    userService.saveBatch(users);
}

三、常用注解

1.@TableId

         我们可以从TableId源码中可以看到,我们可以设置两个值,一个是value,一个 type,

value设置字段名
type设置主键模式

(1)value

        回顾到我们之前所创建的User实体中的id属性,在我们MySQL表中,user表的第一列也是id,假如我们把user表中的id修改为uid,再执行插入代码时,看看会出现什么结果

         不出意外,发现我们SQL语句使用的是id字段,由于user表中是uid,所以就无法执行语句,在开发中,也会出现设置的实体类属性和表字段不一致的情况,所有为了解决这种情况,MyBatisPlus提供了@TableId注解

         我们可以使用value属性,将User实体类的id属性改名为user表中对应的uid

public class User {
    @TableId(value="uid")
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

        此时我们再次调用方法

         这时就通过了修改,而mybatisplus所生成是SQL语句也发生了变化

(2)type

        在前面的插入时,我们可以注意到表中的主键生成是利用的雪花算法,如果不想使用使用雪花算法,就可以使用type属性中的不同主键模式

         如果我们想使用自增,那么就需要选择IdType.AUTO来实现自增效果,于此同时,user表也要将主键uid修改为自增模式,然后执行insert方法

查看数据库数据:

        这个时候id值也不在是雪花算法计算出来的了。

         type的其他模式,感兴趣可以去官网查看,这里不做过多赘述

2.@TableField

        同样的,既然有对主键进行备注数据库中字段名的修饰,对于一般字段来说,可以使用TableField来进行备注数据库中字段名

@Data
public class User {

    @TableId(type = IdType.AUTO)
    private Long id;
    @TableField("username")
    private String name;
    private Integer age;
    private String email;
}

结果:

         SQL语句使用的是TabelField所备注的字段username

3.@TableLogic

        这个注释标注的是逻辑删除

        所以我们需要对User实体和user表进行添加字段,

user表:

User实体:

@Data
public class User {

    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @TableLogic
    private Boolean is_delete;
}

 执行的删除操作

         这时可以发现,删除操作生成的是update语句,而不再是delete。使用update语句实现逻辑删除。

四、条件构造器和常用接口

1wapper介绍

图片来源于尚硅谷
  • Wrapper : 条件构造抽象类,最顶端父类
    • AbstractWrapper : 用于查询条件封装,生成 sql where 条件
      • QueryWrapper : 查询条件封装
      • UpdateWrapper Update 条件封装
      • AbstractLambdaWrapper : 使用Lambda 语法
        • LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper
        • LambdaUpdateWrapper Lambda 更新封装Wrapper

2QueryWrapper

QueryWrapper的每个方法返回的值都是QueryWrapper对象,所有每次后面直接‘.’即可

(1)组转查询条件

@Test
public void test01(){
    //查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息
    // SELECT id,username AS name,age,email,is_deleted FROM user WHERE
    // is_deleted=0 AND (username LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("username", "a")
    .between("age", 20, 30)
    .isNotNull("email");
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}

(2)组装排序条件

@Test
public void test02(){
    //按年龄降序查询用户,如果年龄相同则按id升序排列
    //SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE
    //is_deleted=0 ORDER BY age DESC,id ASC
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper
    .orderByDesc("age")
    .orderByAsc("id");
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}

(3)组装删除条件

@Test
public void test03(){
    //删除email为空的用户
    //DELETE FROM user WHERE (email IS NULL)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.isNull("email");
    //条件构造器也可以构建删除语句的条件
    int result = userMapper.delete(queryWrapper);
    System.out.println("受影响的行数:" + result);
}

(4)条件优先级

@Test
public void test04() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
    //UPDATE user SET age=?, email=? WHERE (username LIKE ? AND age > ? OR email IS NULL)
    queryWrapper
    .like("username", "a")
    // gt表示大于
    .gt("age", 20)
    .or()
    .isNull("email");
    User user = new User();
    user.setAge(18);
    user.setEmail("user@atguigu.com");
    int result = userMapper.update(user, queryWrapper);
    System.out.println("受影响的行数:" + result);
}

(5)组装select子句

@Test
public void test05() {
    //查询用户信息的username和age字段
    //SELECT username,age FROM t_user
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.select("username", "age");
    //selectMaps()返回Map集合列表,通常配合select()使用,避免User对象中没有被查询到的列值
    //为null
    List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
    maps.forEach(System.out::println);
}

(6)实现子查询

@Test
public void test06() {
    // 查询id小于等于3的用户信息
    // SELECT id,username AS name,age,email,is_deleted FROM user WHERE (id IN (select id from t_user where id <= 3))
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.inSql("id", "select id from t_user where id <= 3");
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}

3.UpdateWrapper

@Test
public void test07() {
    //将(年龄大于20或邮箱为null)并且用户名中包含有a的用户信息修改
    //组装set子句以及修改条件
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    //lambda表达式内的逻辑优先运算
    updateWrapper
        .set("age", 18)
        .set("email", "user@atguigu.com")
        .like("username", "a")
        .and(i -> i.gt("age", 20).or().isNull("email"));
    //这里必须要创建User对象,否则无法应用自动填充。如果没有自动填充,可以设置为null
    //UPDATE user SET username=?, age=?,email=? WHERE (username LIKE ? AND
    //(age > ? OR email IS NULL))
    //User user = new User();
    //user.setName("张三");
    //int result = userMapper.update(user, updateWrapper);
    //UPDATE t_user SET age=?,email=? WHERE (username LIKE ? AND (age > ? OR
    //email IS NULL))
    int result = userMapper.update(null, updateWrapper);
    System.out.println(result);
}

4condition

        在真正开发的过程中,组装条件是常见的功能,而这些条件数据来源于用户输入,是可选的,因 此我们在组装这些条件时,必须先判断用户是否选择了这些条件,若选择则需要组装该条件,若没有选择则一定不能组装,以免影响SQL 执行的结果

        思路一: 

@Test
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 参数的重载方法构建查询条件,简化代码的编写
@Test
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);
}

5LambdaQueryWrapper

@Test
public void test09() {
    //定义查询条件,有可能为null(用户未输入)
    String username = "a";
    Integer ageBegin = 10;
    Integer ageEnd = 24;
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    //避免使用字符串表示字段,防止运行时错误
    queryWrapper
        .like(StringUtils.isNotBlank(username), User::getName, username)
        .ge(ageBegin != null, User::getAge, ageBegin)
        .le(ageEnd != null, User::getAge, ageEnd);
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}

6LambdaUpdateWrapper

@Test
public void test10() {
    //组装set子句
    LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper
        .set(User::getAge, 18)
        .set(User::getEmail, "user@atguigu.com")
        .like(User::getName, "a")
        .and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail)); 
    //lambda表达式内的逻辑优先运算
    User user = new User();
    int result = userMapper.update(user, updateWrapper);
    System.out.println("受影响的行数:" + result);
}

五、分页功能

1.分页插件

(1)配置

在项目目录下创建config文件夹,在config文件夹中创建MybatisPlusConfig类,配置拦截器

@Configuration
public class MybatisPlusConfig {
    // 分页插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new
                PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

(2)测试 

@Test
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());
}

2.xml自定义分页

(1)UserMapper中定义接口方法

/**
* 根据年龄查询用户列表,分页显示
* @param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位
* @param age 年龄
* @return 返回分页对象IPage
*/
IPage<User> selectPageVo(@Param("page") Page<User> page, @Param("age")Integer age);

(2)UserMapper.xml中编写SQL

<!--SQL片段,记录基础字段-->
<sql id="BaseColumns">id,name,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>

(3)测试

@Test
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());
}

======THE END======

感谢阅读,本文章仅为个人学习笔记使用 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

摸鱼儿hzj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值