笔记-MyBatis-Plus-基础

90 阅读7分钟

一、快速入门

  1. 创建表结构

  2. 创建实体类【不用加@AllArgsConstructor@NoArgsConstructor注解】

    @Data
    public class User {
        private Long id;
        private String name;
        private String password;
        private Integer age;
        private String tel;
    }
    
  3. 定义Mapper接口【只需继承BaseMapper就可以实现单表的 CRUD 操作】

    @Mapper
    public interface UserMapper extends BaseMapper<User>{}
    
  4. 【可选】为了方便观察MP框架执行的数据库操作,可以在application.yaml中配置MP的日志,将SQL输出到控制台

    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启mp日志,将sql输出到控制台
    

二、BaseMapper常用方法

  1. 新增操作

    @SpringBootTest
    public class MPTest{
        @Resource
        private UserMapper userMapper;
    ​
        @Test
        void testInsert(){
            User user = new User();
            user.setName("张三");
            user.setPassword("123456");
            user.setAge(12);
            user.setTel("13812345678");
            user.setOnline("1");
            //调用BaseMapper中提供的insert方法
            userMapper.insert(user);
        }
    }
    
  2. 根据id删除【单个】

    @SpringBootTest
    public class MPTest{
        @Resource
        private UserMapper userMapper;
        
        @Test
        void testDeleteById(){
            //根据id删除数据
            int i = userMapper.deleteById(1624945956237721601L);
        }
    }
    
  3. 根据id删除【批量】

    @SpringBootTest
    public class MPTest{
        @Resource
        private UserMapper userMapper;
        
        @Test
        void testDeleteBatchIds(){
            int batchIds = userMapper.deleteBatchIds(Arrays.asList(1625061142848167937L, 1625061824372146177L));
        }
    }
    
  4. 根据id修改

    @SpringBootTest
    public class MPTest{
        @Resource
        private UserMapper userMapper;
        
        @Test
        void testUpdateById(){
            User user=new User();
            user.setId(2625307405933957121L);
            user.setName("张三");
            int i=userMapper.updateById(user);
        }
    }
    
  5. 根据id查询【单个】

    @SpringBootTest
    public class MPTest{
        @Resource
        private UserMapper userMapper;
        @Test
        void testSelectById(){
            User user = userMapper.selectById(1625307405933957121L);
        }
    }
    
  6. 根据id查询【批量】

    @SpringBootTest
    public class MPTest{
        @Resource
        private UserMapper userMapper;
        
        @Test
        void testSelectBatchIds(){
            List<User> users = userMapper.selectBatchIds(Arrays.asList(1625307405933957121L, 1625310776384380930L));
        }
    }
    
  7. 分页查询

    @SpringBootTest
    public class MPTest{
        @Resource
        private UserMapper userMapper;
        
        @Test
        void testSelectPage(){
            //分页查询条件对象
            Page<User> page = new Page<>(1,5);
            //分页查询
            userMapper.selectPage(page,null);
            //总记录数
            long total = page.getTotal();
            //分页结果数据
            List<User> records = page.getRecords();
        }
    }
    

    需要提前配置MP框架的分页拦截器

    package com.suenchi.config;
    ​
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    ​
    @Configuration
    public class MPConfiguration {
    ​
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor(){
            MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
            //添加分页拦截器,实现分页查询功能
            mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
            return mybatisPlusInterceptor;
        }
    ​
    }
    

三、常用注解

  1. @TableName:映射实体类和表的对应关系

    @TableName("t_user")
    public class User{
        private Long id;
        //......
    }
    

    以下情况MP会自动进行映射,注解@TableName可以省略:

    1. 类名和表名一致
    2. 类名采用驼峰命名法(UserOptLog),表名使用对应的下划线分割命名(user_opt_log)
  2. @TableField:映射实体类属性和表字段的对应关系

    public class User{
        //当前属性对应的字段为pwd
        @TableField(value="pwd")
        private String password;
        
        //当前属性在表中没有对应的字段
        @TableField(exist=false)
        private String online;
    }
    
    1. 相关属性

      1. value:设置表字段名称
      2. exist:设置属性在表字段中是否存在,默认为true
    2. 以下情况MP会自动进行映射,注解@TableField可以省略:

      1. 属性名和字段名一致
      2. 属性名采用驼峰命名法(CreateTime),字段名使用对应的下划线分割命名(create_time)
  3. @TableId:映射实体类属性和表主键字段的对应关系,还能设置主键的生成策略

    public class User{
        @TableId(type=IdType.AUTO)
        private Long id;
    }
    
    1. 相关属性

      1. value:设置表主键字段名称
      2. type:设置主键的生成策略,值参照IdType的枚举值
    2. 主键生成策略

      1. AUTO:使用数据库id自增策略控制id生成
      2. NONE:不设置id生成策略
      3. INPUT:用户手工输入id
      4. ASSIGN_ID:雪花算法生成id(可兼容数值型与字符串型)
      5. ASSIGN_UUID:以UUID生成算法作为id生成策略
    3. 雪花算法:是Twitter公司推出的专门针对分布式ID的解决方案

    4. 为了简化开发,我们可以在application.yaml中配置全局的主键生成策略,之后在实体类中就无须再配置了

      mybatis-plus:
        global-config:
          db-config:
            id-type: assign_id #全局设置主键生成策略
      

四、常用条件构造器

  1. 条件构造器,即Wrapper,其作用是控制最终生成的SQL语句的条件部分,如下:

    1. select ___ from tb where ___ order by ___
    2. update tb set ___ where ___
    3. delete from tb where ___
  2. 常用Wrapper

    1. QueryWrapper:控制最终生成的查询、删除类的SQL语句

      //条件构造器
      QueryWrapper<User> queryWrapper=new QueryWrapper<>();
      queryWrapper.select("id","name");
      queryWrapper.gt("age",20);
      queryWrapper.eq(tel!=null,"tel",tel);   //动态添加查询条件
      queryWrapper.like("name","zhangsan");
      queryWrapper.orderByAsc("id");
      //执行查询
      List<User> userList=userMapper.selectList(queryWrapper);
      
      1. 以上对应的预编译SQL:select id,name from user where age>? and tel=? and name like ? order by id asc
      2. 使用QueryWrapper设置条件,其实是通过字符串指定的字段名,如果指定的字段名有误,在编译阶段不会报错,而在程序运行期间才会抛出异常
    2. LambdaQueryWrapper:为了解决QueryWrapper的问题而出现的,能保证在编译阶段就发现错误

      //条件构造器
      LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();
      lambdaQueryWrapper.select(User::getId,User::getName);
      lambdaQueryWrapper.gt(User::getAge,20);
      lambdaQueryWrapper.eq(tel!=null,User::getTel,tel);  //动态添加查询条件
      lambdaQueryWrapper.like(User::getName,"itcast");
      lambdaQueryWrapper.orderByAsc(User::getId);
      //执行查询
      List<User> userList=userMapper.selectList(lambdaQueryWrapper);
      

      实际开发中,我们都用LambdaQueryWrapper来取代QueryWrapper

    3. UpdateWrapper:控制最终生成的更新类的SQL语句

      //条件构造器
      UpdateWrapper<User> updateWrapper=new UpdateWrapper<>();
      updateWrapper.set("name","zhangsan");
      updateWrapper.gt("age",18);
      //执行更新
      userMapper.update(null,updateWrapper);  //使用 BaseMapper 的 update 方法设置 set 条件时,既可以通过第一个参数(实体对象)设置,也可以通过第二个参数(UpdateWrapper)设置,这里是通过第二个参数设置的
      
      1. 以上对应的预编译SQL:update user set name=? where age>?
      2. 同QueryWrapper,也是通过字符串指定的字段名,如果指定的字段名有误,在编译阶段不会报错,而在程序运行期间才会抛出异常
    4. LambdaUpdateWrapper:为了解决UpdateWrapper的问题而出现的,能保证在编译阶段就发现错误

      //条件构造器
      LambdaUpdateWrapper<User> lambdaUpdateWrapper=new LambdaUpdateWrapper<>();
      lambdaUpdateWrapper.set(User::getName,"zhangsan");
      lambdaUpdateWrapper.gt(User::getAge,18);
      //执行更新
      userMapper.update(null,lambdaUpdateWrapper);
      

      实际开发中,我们都用LambdaUpdateWrapper来取代UpdateWrapper

  3. 【技巧】在定义条件构造器时,可以使用链式编程风格

    QueryWrapper<User> queryWrapper=new QueryWrapper<>();
    queryWrapper
        .select("id", "name")
        .gt("age", 20)
        .eq(tel != null, "tel", tel)
        .like("name", "zhangsan")
        .orderByAsc("id");
    
  4. 【扩展】为了进一步增强MyBatis的功能,我们可以在Mapper中声明方法时,利用MP提供的Wrapper条件构造器对象作为参数

    @Mapper
    public interface UserMapper extends BaseMapper<User>{
        @Select("select * from t_user ${ew.customSqlSegment}")
        List<User> findByCondition(@Param("ew") Wrapper<User> queryWrapper);
    }
    
    1. 上述通过@Param注解为Wrapper对象指定了别名,
    2. customSqlSegment为固定写法,底层会调用Wrapper对象的getCustomSqlSegment()方法获取对应的SQL片段

五、MP 对 Service 层的支持

  1. 业务接口继承 MP 提供的 IService 接口

    public interface UserService extends IService<User>{}
    
  2. 业务实现类继承 MP 提供的 ServiceImpl类

    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{}
    
  3. 对于单表操作,直接调用 MP 提供的 Service 中的方法即可

  4. 当 MP 中 Service 中提供的方法不能满足要求时,可以自己扩展方法:

    public interface UserService extends IService<User>{
        public void myMethod();
    }
    
    public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService{
        public void myMethod(){
            //在业务实现类中,通过调用getBaseMapper方法能够获得对应的Mapper对象
            UserMapper userMapper=this.getBaseMapper();
            //业务...
            User user = userMapper.selectById(1625307405933957121L);
        }
    }
    

    在业务实现类中,通过调用getBaseMapper方法能够获得对应的Mapper对象

六、逻辑删除【扩展】

  1. 物理删除指的是直接将数据从数据库中删除,执行的是delete语句

  2. 逻辑删除指的是修改数据中的某个字段,使其表示为已删除状态,执行的是update语句

    员工编号姓名工号deleted
    1张三95011
    2李四95020
    3王五95030
  3. 对于那些重要的、后期可能需要恢复的数据,可以考虑使用逻辑删除

  4. MP 框架已经对逻辑删除提供了实现,我们直接使用即可

    1. 在表中添加逻辑删除字段 deleted

    2. 在 application.yaml 中配置逻辑删除相关配置项

      mybatis-plus:
        global-config:
          db-config:
              logic-delete-field: deleted # 逻辑删除全局属性名
              logic-delete-value: 1 # 逻辑删除全局值
              logic-not-delete-value: 0 # 逻辑未删除全局值
      
    3. 在实体类中添加逻辑删除属性,并标识@TableLogic注解

      @Data
      public class UserInfo{
          private Long id;
          private String name;
          private Integer age;
          @TableLogic
          private Integer deleted; //删除标识:1已删除,0未删除
      }
      

    之后调用BaseMapper的删除方法时,发现底层调用的是update语句;调用查询方法时,会自动追加查询条件deleted=0

七、MyBatisX【扩展】

利用MaBatisX代码生成器,能根据表结构,反向生成对应的实体类、Mapper、Service等【参考其他文章】