Mybatis-plus快速入门(2)

CSDN话题挑战赛第2期
参赛话题:学习笔记

Mybatis-plus

学习之路,长路漫漫,需要您的陪伴。
关注一波,您的关注是我最大的动力。

在这里插入图片描述

文章目录接上篇文章 Mybatis-plus快速入门(1)

四、常用注解

1、@TableName

① 问题

也许有同学发现了,在上一篇文章 Mybatis-plus快速入门(1) 中我们使用Mybatis-plus进行简单的CRUD时并没有指定表名,只是在Mapper接口继承BaseMapper时,设置了泛型User,而操作的表为User表

由此可知,MyBatis-Plus在确定操作的表时,由BaseMapper的泛型决定,即实体类型决定,且默认操作的表名和实体类型的类名一致

② 测试

测试如下,将user表改为t_user表,测试查询功能

程序抛出异常,Table ‘mybatis_plus.user’ doesn’t exist,因为现在的表名为t_user,而默认操作的表名和实体类型的类名一致,即user表

在这里插入图片描述

③ 添加@TableName

在实体类类型上添加@TableName(“t_user”),标识实体类对应的表,即可成功执行SQL语句

在这里插入图片描述

④ 全局配置

在开发的过程中,我们经常遇到以上的问题,即实体类所对应的表都有固定的前缀,例如t_ 或tbl_

此时,可以使用MyBatis-Plus提供的全局配置,在application.yaml中为实体类所对应的表名设置默认的前缀,那么就不需要在每个实体类上通过@TableName标识实体类对应的表

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    #设置Mybatis-plus全局配置
    global-config:
      db-config:
        #设置实体类所对应表的统一前缀
        table-prefix: t_
        #设置统一的主键生成策略

2、@TableId

我们在使用MyBatis-Plus实现CRUD时,会默认将id作为主键列,并在插入数据时,默认基于雪花算法的策略生成id。

① 问题

若实体类和表中表示主键的不是id,而是其他字段,例如uid,MyBatis-Plus会自动识别uid为主键列吗?

我们实体类中的属性id改为uid,将表中的字段id也改为uid,测试添加功能

程序抛出异常,Field ‘uid’ doesn’t have a default value,说明MyBatis-Plus没有将uid作为主键赋值
在这里插入图片描述

② 添加@TableId

在实体类中uid属性上通过@TableId将其标识为主键,即可成功执行SQL语句
在这里插入图片描述

③ @TableId的value属性

若实体类中主键对应的属性为id,而表中表示主键的字段为uid,此时若只在属性id上添加注解@TableId,则抛出异常Unknown column ‘id’ in ‘field list’,即MyBatis-Plus仍然会将id作为表的主键操作,而表中表示主键的是字段uid

此时需要通过@TableId注解的value属性,指定表中的主键字段,@TableId(“uid”)或@TableId(value=“uid”)

在这里插入图片描述

④ @TableId的type属性

type属性用来定义主键策略,这里我们介绍其中的两种常用的:

描述
IdType.ASSIGN_ID(默认)基于雪花算法的策略生成数据id,与数据库id是否设置自增无关
IdType.AUTO使用数据库的自增策略,注意,该类型请确保数据库设置了id自增

可在实体类对应的字段上进行设置:

	//将属性所对应的字段指定为主键
    //tableId注解的value属性用于指定主键的字段
    //tableId注解的type属性用于设置主键生成策略
    @TableId(value = "uid",type = IdType.AUTO)
    private Long uid;

也可在application.yaml中配置全局主键策略:

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    #设置Mybatis-plus全局配置
    global-config:
      db-config:
        #设置实体类所对应表的统一前缀
        table-prefix: t_
        #设置统一的主键生成策略
        id-type: auto

⑤ 雪花算法

雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的

主键的有序性。

核心思想:

长度共64bit(一个long型)。

首先是一个符号位,1bit标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负

数是1,所以id一般是正数,最高位是0。

41bit时间截(毫秒级),存储的是时间截的差值(当前时间截 - 开始时间截),结果约等于69.73年。

10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID,可以部署在1024个节点)。

12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID)。

在这里插入图片描述

优点

整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞,并且效率较高

3、@TableField

我们可以发现,MyBatis-Plus在执行SQL语句时,要保证实体类中的属性名和表中的字段名一致

如果实体类中的属性名和字段名不一致的情况,会出现什么问题呢?

情况①

若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格

例如实体类属性userName,表中字段user_name

此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格

相当于在MyBatis中配置

情况②

若实体类中的属性和表中的字段不满足情况1

例如实体类属性name,表中字段username

此时需要在实体类属性上使用@TableField(“username”)设置属性所对应的字段名

在这里插入图片描述

4、@TableLogic

① 逻辑删除

  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
  • 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
  • 使用场景:可以进行数据恢复

② 实现逻辑删除

步骤一、在User表中增加一个int型的字段is_deleted,初始值为0,代表未删除
在这里插入图片描述

步骤二、实体类中添加逻辑删除属性

在这里插入图片描述

步骤三、测试

测试删除功能,真正执行的是修改,从日志输出的sql语句可以看出

UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0

测试查询功能,被逻辑删除的数据默认不会被查询

SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0

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

1、wrapper介绍

在这里插入图片描述

  • Wrapper : 条件构造抽象类,最顶端父类

    • AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件

      • QueryWrapper : 查询条件封装

      • UpdateWrapper : Update 条件封装

      • AbstractLambdaWrapper : 使用Lambda 语法

        • LambdaQueryWrapper :用于Lambda语法使用的查询Wrapper

        • LambdaUpdateWrapper : Lambda 更新封装Wrapper

2、QueryWrapper

① 组装查询条件

    @Test
    public void test01() {
        //查询用户名包含a,年龄在20-30之间,邮箱信息不为null的用户信息
        //日志输出的sql语句:SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("user_name",'a')
                .between("age",20,30).isNotNull("email");
        List<User> list = usermapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

② 组装排序条件

    @Test
    public void test02() {
        //查询用户信息,按照年龄进行降序排序,若年龄相同,则按照id升序排序
        //日志输出的sql语句:SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASC
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("age")
                .orderByAsc("uid");
        List<User> list = usermapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

③ 组装删除条件

    @Test
    public void test03() {
        //删除邮箱地址为null的用户信息
        //增加了逻辑删除,所以变化为更新了
        //日志输出的sql语句:UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull("email");
        int res = usermapper.delete(queryWrapper);
        System.out.println("res = " + res);

    }

④ 条件的优先级

    @Test
    public void test04() {
        //将(年龄大于20并且名字中含有a)或邮箱为null的用户信息修改
        //日志输出的sql语句:UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (age > ? AND user_name LIKE ? OR email IS NULL)
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("age",20).like("user_name",'a')
                .or().isNull("email");
        User user = new User();
        user.setName("小明");
        user.setEmail("test@atguigu.com");
        int res = usermapper.update(user, queryWrapper);
        System.out.println("res = " + res);
    }
    @Test
    public void test05() {
        //将名字中含有a并且(年龄大于20或邮箱为null)的用户信息修改
        //日志输出的sql语句:UPDATE t_user SET user_name=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //lambda表达式内的逻辑优先运算
        queryWrapper.like("user_name",'a')
                .and(i->i.gt("age",20).or().isNull("email"));
        User user = new User();
        user.setName("Sandy");
        user.setEmail("test@atguigu.com");
        int res = usermapper.update(user, queryWrapper);
        System.out.println("res = " + res);
    }

⑤ 组装select语句

    @Test
    public void test06() {
        //查询用户的用户名,年龄,邮箱
        //日志输出的sql语句:SELECT user_name,age,email FROM t_user WHERE is_deleted=0
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("user_name","age","email");
        //查询的是部分字段,没必要直接对应实体类对象,直接map集合即可
        List<Map<String, Object>> maps = usermapper.selectMaps(queryWrapper);
        maps.forEach(System.out::println);
    }

⑥ 实现子查询

    @Test
    public void test07() {
        //通过子查询查询用户id小于等于10的用户信息
        //日志输出的查询语句:SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (Select uid from t_user where uid <= 10))
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("uid","Select uid from t_user where uid <= 10");
        List<User> list = usermapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

3、UpdateWrapper

    @Test
    public void test08() {
        //将名字中含有a并且(年龄大于20或邮箱为null)的用户信息修改
        //日志输出的sql语句:UPDATE t_user SET user_name=?,email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))
        //UpdateWrapper设置修改条件的同时也可设置修改字段
        UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
        userUpdateWrapper.like("user_name",'a')
                .and(i->i.gt("age",20).or().isNull("email"));
        userUpdateWrapper.set("user_name","小黑").set("email","xiaohei@atguigu.com");
        int res = usermapper.update(null, userUpdateWrapper);
        System.out.println("res = " + res);
    }

4、condition

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

思路①

	@Test
    public void test09() {
        //开发中的场景
        //日志输出的sql语句:SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age < ?)
        //定义查询条件,有可能为null(用户未输入或未选择)
        String userName="小";
        Integer ageBegin=null;
        Integer ageEnd=30;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        if(StringUtils.isNotBlank(userName)) {
            queryWrapper.like("user_name",userName);
        }
        if(ageBegin!=null) {
            queryWrapper.gt("age",ageBegin);
        }
        if(ageEnd!=null) {
            queryWrapper.lt("age",ageEnd);
        }
        List<User> list = usermapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

思路②

    @Test
    public void test10() {
        //相比test09更方便的写法
        //日志输出的sql语句:SELECT uid,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age < ?)
        String userName="小";
        Integer ageBegin=null;
        Integer ageEnd=30;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(userName),"user_name",userName)
                .gt(ageBegin!=null,"age",ageBegin)
                .lt(ageEnd!=null,"age",ageEnd);

        List<User> list = usermapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

5、LambdaQueryWrapper

    @Test
    public void test11() {
        //LambdaQueryWrapper为了防止字段名写错,可以使用函数式接口访问实体类中的某一个属性所对应的字段名
        //日志输出的sql语句
        String userName="小";
        Integer ageBegin=null;
        Integer ageEnd=30;
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(StringUtils.isNotBlank(userName),User::getName,userName)
                .gt(ageBegin!=null,User::getAge,ageBegin)
                .lt(ageEnd!=null,User::getAge,ageEnd);
        List<User> list = usermapper.selectList(lambdaQueryWrapper);
        list.forEach(System.out::println);

    }

6、LambdaUpdateWrapper

    @Test
    public void test12() {
        //将名字中含有a并且(年龄大于20或邮箱为null)的用户信息修改
        //日志输出的sql语句:UPDATE t_user SET user_name=?,email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))        //UpdateWrapper设置修改条件的同时也可设置修改字段
        LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.like(User::getName,'a')
                .and(i->i.gt(User::getAge,20).or().isNull(User::getEmail));
        lambdaUpdateWrapper.set(User::getName,"小黑").set(User::getEmail,"xiaohei@atguigu.com");
        int res = usermapper.update(null, lambdaUpdateWrapper);
        System.out.println("res = " + res);
    }



点赞,关注,收藏,您的支持是我更新的最大动力!!!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zoeil

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

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

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

打赏作者

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

抵扣说明:

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

余额充值