• MybatisPlus常用总结


    1. 创建表

    CREATE TABLE `user` (
    `id` bigint(20) NOT NULL COMMENT '主键ID',
    `name` varchar(30) DEFAULT NULL COMMENT '姓名',
    `age` int(11) DEFAULT NULL COMMENT '年龄',
    `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    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');

    2. pom

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.5.1</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
        </dependencies>

    3. application.yml

    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mydatabase?serverTimezone=UTC&useSSL=false
    spring.datasource.username=root
    spring.datasource.password=123456
    mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl mybatis-plus.mapper-locations=classpath:mapper/*.xml

    4. 实体类

    @Data
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }

    5. 添加mapper

    public interface UserMapperr extends BaseMapper<User> {
        //自定义查询 Map
    <String,Object> selectMapById(Long id); }

    6. 测试不同的方法

    @SpringBootTest
    class ApplicationTests {
    
        @Autowired
        private UserMapperr userMapperr;
    
        @Test
        void contextLoads() {
            //通过条件构造器查询一个List集合,若没有条件,可以设置null为参数
            List<User> users = userMapperr.selectList(null);
            users.forEach(System.out::println);
        }
    
        @Test
        void testInsert(){
            User user = new User();
            user.setName("张三");
            user.setAge(23);
            user.setEmail("zhangsan@qq.com");
            //插入方法,默认生成id使用雪花算法,生成分布式id
            //INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
            int result = userMapperr.insert(user);
            System.out.println("result " + result);
            System.out.println("id " + user.getId());
        }
    
        @Test
        void testDelete(){
            //1. 通过id删除用户信息 DELETE FROM user WHERE id=?
        /*    int result = userMapperr.deleteById(1516412322837491713L);
            System.out.println("result " + result);*/
    
            //2. 根据map集合中所设置的条件删除用户信息  DELETE FROM user WHERE name = ? AND age = ?
        /*    Map<String, Object> map = new HashMap<>();
            map.put("name", "Billie");
            map.put("age", 24);
            int result = userMapperr.deleteByMap(map);
            System.out.println("result " + result);*/
    
            //3. 通过多个id实现批量删除 DELETE FROM user WHERE id IN ( ? , ? , ? )
            List<Long> list = Arrays.asList(1L, 2L, 3L);
            int result = userMapperr.deleteBatchIds(list);
            System.out.println("result " + result);
        }
    
        @Test
        void testUpdate(){
            //修改用户信息 UPDATE user SET name=?, email=? WHERE id=?
            User user = new User();
            user.setId(4L);
            user.setName("李四");
            user.setEmail("lisi@atguigu.com");
            int result = userMapperr.updateById(user);
            System.out.println("result " + result);
        }
    
        @Test
        void testSelect(){
            //1 .通过id查询用户信息 SELECT id,name,age,email FROM user WHERE id=?
        /*    User user = userMapperr.selectById(1L);
            System.out.println("user " + user);*/
    
            //2. 根据多个id查询多个用户信息 SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
        /*    List<Long> longs = Arrays.asList(1L, 2L, 3L);
            List<User> users = userMapperr.selectBatchIds(longs);
            users.forEach(System.out::println);*/
    
            //3. 根据map集合中的条件查询用户信息 SELECT id,name,age,email FROM user WHERE name = ? AND age = ?
        /*    HashMap<String, Object> map = new HashMap<>();
            map.put("name","Jack");
            map.put("age",20);
            List<User> users = userMapperr.selectByMap(map);
            users.forEach(System.out::println);*/
    
            //4. 查询所有数据 SELECT id,name,age,email FROM user
         /*   List<User> users = userMapperr.selectList(null);
            users.forEach(System.out::println);*/
    
            //5. 使用自定义的查询 select * from user where id = ?
            Map<String, Object> map = userMapperr.selectMapById(1L);
            System.out.println("map " + map);
        }
    }

      使用自定义查询需要写mapper文件

    <mapper namespace="com.lewang.mapper.UserMapperr">
        <select id="selectMapById" resultType="map">
            select * from user where id = #{id}
        </select>
    </mapper>

    7. 通用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     

      (1)IService  

      MyBatis-Plus中有一个接口 IService和其实现类 ServiceImpl,封装了常见的业务层逻辑详情查看源码IService和ServiceImpl

      (2)创建Service接口和实现类

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

     (3)测试count和批量添加

        @Autowired
        private UserService userService;
    
        @Test
        void testService(){
            // SELECT COUNT( * ) FROM user
            long count = userService.count();
            System.out.println("总数量:" + count);
        }
    
        @Test
        void testSaveBatch(){
            // SQL长度有限制,海量数据插入单条SQL无法实行,因此MP将批量插入放在了通用Service中实现,而不是通用Mapper
           //INSERT INTO user ( id, name, age ) VALUES ( ?, ?, ? )
            ArrayList<User> list = new ArrayList<>();
            for (int i = 0; i < 5; i++) {
                User user = new User();
                user.setName("abc" + i);
                user.setAge(10 + i);
                list.add(user);
            }
            userService.saveBatch(list);
        }

    8. 当表名和实体类名不对应时

      就会发生查询异常

      (1)可以在实体类上使用注解声明

    @TableName("t_user")
    @Data
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }

      数据库中的表名为t_user,实体类名为User时,可以在实体类上声明对应的表名

      (2)通过全局配置解决问题

    mybatis-plus:
      configuration:
      # 配置MyBatis日志
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      global-config:
        db-config:
        # 配置MyBatis-Plus操作表的默认前缀
          table-prefix: t_

    9. @TableId

      (1)经过以上的测试,MyBatis-Plus在实现CRUD时,会默认将id作为主键列,并在插入数据时,默认基于雪花算法的策略生成id

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

    @TableName("uuser")
    @Data
    public class User {
        private Long uid;
        private String name;
        private Integer age;
        private String email;
    }

      当表中和实体类中都是用uid时,插入时会发生异常。使用@TableId修饰uid属性将其标识为主键,即可成功执行SQL语句。

      (2)@TableId的value属性

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

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

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

      (3)@TableId的type属性

        IdType.ASSIGN_ID(默认)  基于雪花算法的策略生成数据id,与数据库id是否设置自增无关

        IdType.AUTO  使用数据库的自增策略,注意,该类型请确保数据库设置了id自增,否则无效

        IdType.ASSIGN_UUID  基于UUID生成id

    @TableName("uuser")
    @Data
    public class User {
      //设置自增策略 @TableId(value
    = "uid",type = IdType.AUTO) private Long id; private String name; private Integer age; private String email; }

      配置全局主键策略

    mybatis-plus:
        configuration:
            # 配置MyBatis日志
            log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
        global-config:
            db-config:
                # 配置MyBatis-Plus操作表的默认前缀
                table-prefix: t_
                # 配置MyBatis-Plus的主键策略
                id-type: auto            

     10. @TableField

      MyBatis-Plus在执行SQL语句时,要保证实体类中的属性名和表中的字段名一致,如果实体类中的属性名和字段名不一致的情况,就会插入异常

      (1)若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格,例如实体类属性userName,表中字段user_name,此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格,相当于在MyBatis中配置。

      (2)若实体类中的属性和表中的字段不满足情况1,例如实体类属性username,表中字段name,此时需要在实体类属性上使用@TableField("name")设置属性所对应的字段名

    @TableName("uuser")
    @Data
    public class User {
        @TableId(value = "uid",type = IdType.AUTO)
        private Long id;
        @TableField("name")
        private String username;
        private Integer age;
        private String email;
    }

    11. @TableLogic  

      (1)逻辑删除

        物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据

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

      (2)实现逻辑删除
        step1:数据库中创建逻辑删除状态列,设置默认值为0

        step2:实体类中添加逻辑删除属性

    @TableName("uuser")
    @Data
    public class User {
        @TableId(value = "uid",type = IdType.AUTO)
        private Long id;
        @TableField("name")
        private String username;
        private Integer age;
        private String email;
    
        @TableLogic
        private Integer isDeleted;
    }

        step3:测试

        测试删除功能,真正执行的是修改

    UPDATE uuser SET is_deleted=1 WHERE uid IN ( ? , ? , ? ) AND is_deleted=0

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

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

    12. 条件构造器和常用接口

       wapper介绍

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

      (1)QueryWrapper

        例1:组装查询条件

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

       例2:组装排序条件

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

       例3:组装删除条件

        @Test
        void test03(){
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.isNull("email");
         //使用逻辑删除   UPDATE uuser SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)
            int delete = userMapperr.delete(wrapper);
            System.out.println(delete);
        }

       例4:修改

        @Test
        void test04(){
            QueryWrapper<User> wrapper = new QueryWrapper<>();
    ////将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
    //UPDATE uuser SET name=?, email=? WHERE is_deleted=0 AND (age > ? AND name LIKE ? OR email IS NULL) wrapper.gt("age",20).like("name","a") .or() .isNull("email"); User user = new User(); user.setUsername("小木"); user.setEmail("ll@qq.com"); int update = userMapperr.update(user, wrapper); System.out.println("更新结果:" + update); }

        条件优先级

        @Test
        void test05(){
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            //将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改
            //UPDATE uuser SET name=?, email=? WHERE is_deleted=0 AND (name LIKE ? AND (age > ? OR email IS NULL))
            //lambda表达式内的逻辑优先运算
            wrapper.like("name","a")
                    .and(i->i.gt("age",20).or().isNull("email"));
            User user = new User();
            user.setUsername("西斯");
            user.setEmail("eee@qq.com");
            int update = userMapperr.update(user, wrapper);
            System.out.println("update" + update);
        }

       例5:组装select子句

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

       例6:实现子查询

        @Test
        void test07(){
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            //查询id小于等于3的用户信息
            //SELECT uid AS id,name AS username,age,email,is_deleted FROM uuser WHERE is_deleted=0 AND (uid IN (select uid from uuser where uid <= 3))
            wrapper.inSql("uid","select uid from uuser where uid <= 3");
            List<User> users = userMapperr.selectList(wrapper);
            users.forEach(System.out::println);
        }

      (2)UpdateWrapper

        @Test
        void test08(){
            UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
            //将(年龄大于20或邮箱为null)并且用户名中包含有a的用户信息修改
            //UPDATE uuser SET name=?,email=? WHERE is_deleted=0 AND (name LIKE ? AND (age > ? OR email IS NULL))
            updateWrapper.like("name","a")
                    .and(i->i.gt("age",10).or().isNull("email"));
            updateWrapper.set("name","heheee").set("email","faefa@qq.com");
            int update = userMapperr.update(null, updateWrapper);
            System.out.println("update:" + update);
        }

     13. condition

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

      例1

        @Test
        void test09(){
            String username = "";
            Integer ageBegin = null;
            Integer ageEnd = 30;
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            if (StringUtils.isNotBlank(username)){
                wrapper.like("name",username);
            }
            if (ageBegin != null){
                wrapper.ge("age",ageBegin);
            }
            if (ageEnd !=null){
                wrapper.le("age",ageEnd);
            }
            //SELECT uid AS id,name AS username,age,email,is_deleted FROM uuser WHERE is_deleted=0 AND (age <= ?)
            List<User> users = userMapperr.selectList(wrapper);
            users.forEach(System.out::println);
        }

      (2)上面的实现方案没有问题,但是代码比较复杂,我们可以使用带condition参数的重载方法构建查询条件,简化代码的编写

        @Test
        void test10(){
            String username = "a";
            Integer ageBegin = null;
            Integer ageEnd = 30;
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.like(StringUtils.isNotBlank(username),"name",username)
                    .ge(ageBegin != null,"age",ageBegin)
                    .le(ageEnd != null,"age",ageEnd);
            //SELECT uid AS id,name AS username,age,email,is_deleted FROM uuser WHERE is_deleted=0 AND (name LIKE ? AND age <= ?)
            List<User> users = userMapperr.selectList(wrapper);
            users.forEach(System.out::println);
        }

    14. LambdaQueryWrapper

        @Test
        void test11(){
            String username = "a";
            Integer ageBegin = null;
            Integer ageEnd = 30;
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            //避免使用字符串表示字段,可以直接使用User::getUsername的方式
            queryWrapper.like(StringUtils.isNotBlank(username),User::getUsername,username)
                    .ge(ageBegin != null,User::getAge,ageBegin)
                    .le(ageEnd != null,User::getAge,ageEnd);
            //SELECT uid AS id,name AS username,age,email,is_deleted FROM uuser WHERE is_deleted=0 AND (name LIKE ? AND age <= ?)
            List<User> users = userMapperr.selectList(queryWrapper);
            users.forEach(System.out::println);
        }

     15. LambdaUpdateWrapper

        @Test
        void test12(){
            LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
            //为了防止直接写字符串出现问题,可以使用函数式写法
            updateWrapper.like(User::getUsername,"a")
                    .and(i->i.gt(User::getAge,20).or().isNull(User::getEmail));
            updateWrapper.set(User::getUsername,"huihui").set(User::getEmail,"fdsa@qq.com");
            //UPDATE uuser SET name=?,email=? WHERE is_deleted=0 AND (name LIKE ? AND (age > ? OR email IS NULL))
            int update = userMapperr.update(null, updateWrapper);
            System.out.println("update++++" + update);
        }

    16. 分页相关

      a. 使用内置函数,分页相关数据获取

      (1)分页插件配置

    @Configuration
    @MapperScan("com.lewang.mapper")
    public class MybatisPlusConfig {
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor(){
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            return interceptor;
        }
    }

      (2)分页相关数据获取

        @Test
        void testPage(){
            Page<User> page = new Page<>(3,3);
            //SELECT uid AS id,name AS username,age,email,is_deleted FROM uuser WHERE is_deleted=0 LIMIT ?
            userMapperr.selectPage(page, null);
            List<User> records = page.getRecords();
            records.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());
        }

      b. 自定义分页函数

      (1)UserMapper中定义接口方法

    Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);

      (2)UserMapper.xml中编写SQL

    <mapper namespace="com.lewang.mapper.UserMapperr">
        <select id="selectPageVo" resultType="com.lewang.pojo.User">
            select * from uuser where age > #{age}
        </select>
    </mapper>

      (3)测试

        @Test
        void testSelfPage(){
            Page<User> page = new Page<>(1,5);
            userMapperr.selectPageVo(page,10);
            List<User> userList = page.getRecords();
            userList.forEach(System.out::println);
        }

    17. 通用枚举

      表中的有些字段值是固定的,例如性别(男或女),此时我们可以使用MyBatis-Plus的通用枚举来实现

      (1)数据库表添加字段sex

       (2)创建通用枚举类型

    @Getter
    public enum  SexEnum {
        MALE(1,"男"),
        FEMALE(2,"女");
    
        @EnumValue
        private int sex;
        private String sexName;
    
        SexEnum(int sex, String sexName) {
            this.sex = sex;
            this.sexName = sexName;
        }
    }

      (3)配置扫描通用枚举

    # 配置扫描通用枚举
    mybatis-plus.type-enums-package=com.lewang.enums

      (4)在实体类上使用属性使用枚举类型

    @TableName("uuser")
    @Data
    public class User {
        @TableId(value = "uid",type = IdType.AUTO)
        private Long id;
        @TableField("name")
        private String username;
        private Integer age;
        private String email;
    
        private SexEnum sex;
    
        @TableLogic
        private Integer isDeleted;
    }

      (5)测试

        @Test
        void testEnum(){
            User user = new User();
            user.setUsername("enum");
            user.setAge(20);
            user.setSex(SexEnum.MALE);
            //INSERT INTO uuser ( name, age, sex ) VALUES ( ?, ?, ? )
            int insert = userMapperr.insert(user);
            System.out.println("数据插入:"  + insert);
        }

      表中插入的数据性别是枚举类型

  • 相关阅读:
    【转载】实用VC++6.0插件
    关于无标题栏窗口拖动的问题
    VC6配置CXimage库
    扎实基础深入篇(七):函数和类没那么复杂
    扎实基础深入篇(六):while循环带动生产力
    扎实基础深入篇(五):字典也就是个弟弟
    扎实基础深入篇(四):听说if语句很叼?
    lxml类库的xpath的使用
    json与re的再次复习
    python基础汇总(四)
  • 原文地址:https://www.cnblogs.com/homle/p/16167830.html
Copyright © 2020-2023  润新知