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

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

 

posted on 2022-04-19 22:47  homle  阅读(293)  评论(0编辑  收藏  举报