MyBaits-Plus

  • Lambda表达式
  • 在涉及到多表的查询中,还是需要使用到MyBatis中的原生连接标签collection以及association

MyBatis vs JPA

  • MyBatis优势
    • SQL语句自由控制,灵活,性能高
    • SQL与代码分离,易于阅读和维护
    • 提供XML标签,支持编写动态SQL语句
  • MyBatis劣势
    • 简单的CRUD操作还得写SQL语句
    • XML中有大量的SQL要维护
    • Mybatis自身功能有限,但是支持Plugin
  • JPA优势
    • JPQL(移植性较好)
    • 提供了很多CRUD方法、开发效率高
    • 对象化程度更高

MyBaits-Plus简介

框架结构

MyBatis-Plus框架结构

特性

  • 无侵入,损耗小、强大的CRUD操作
  • 支持Lambda形式调用、支持多种数据库
  • 支持主键自动生成、支持ActiveRecord模式
  • 支持自定义全局通用操作、支持关键词自动转义
  • 内置代码生成器、内置分页插件、内置性能分析插件
  • 内置全局拦截插件、内置Sql注入剥离器

Lombook

入门

  • 建库建表
  • 引入依赖
  • 配置
  • 编码
  • 测试

基本使用

  • SSM传统编程模式
    • 接口中写抽象方法
    • XML或注解写SQL
    • Service中调用接口
    • Controller中调用

MyBatis-Plus 通用Mapper

新增(Create)

  • mp 实体类和数据库的表对应的是驼峰命名 — > 下划线代替驼峰(createTime—>create_time)
  • mp主键默认寻找为id的,
  • 常用注解
    • @Data:用在实体类上,set,get方法
    • @TableName:指定数据库表名
    • @TableId:指定当前属性为主键,mp主键默认寻找属性名为id的
    • @TableFiled:指定当前属性所对应的列名
  • 排除非表字段的三种方式,就是存储在实体类中,在数据库表中无对应的字段。
    • transient:修饰变量
    • static:修饰变量
    • @TableField(exist = false):注解,表示非数据库表中字段

查询(Retrieve)

注意:所有的查询需要的参数都是数据库中表的列名。
以条件构造器作为参数的查询方法(AbstractWrapper)
  • 默认复杂查询中使用的and

  • //创建wrapper对象,QueryWrapper继承自AbstractWrapper
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    /**
    	 * 1、名字中包含雨并且年龄小于40
    	 * name like '%雨%' and age<40
    	 */
    	@Test
    	public void selectByWrapper() {
    		QueryWrapper<User> queryWrapper = new QueryWrapper<>();//第一种
    //		QueryWrapper<User> query = Wrappers.<User>query();//第二中
    		queryWrapper.like("name","雨").lt("age",40);
    		List<User> userList = userMapper.selectList(queryWrapper);
    		userList.forEach(System.out::println);
    	}
    
select中字段不全部出现的方式(wrapper.select())
  • wrapper.select(String… columns)

  • wrapper.select(Class entityClass, Predicate predicate),用来处理select应该出现的列。

    • @Test
      public void selectByWrapperSupper2() {
         QueryWrapper<User> queryWrapper = new QueryWrapper<>();//第一种
         queryWrapper.like("name","雨").lt("age",40).select(User.class, info->!info.getColumn().equals("create_time")&&
               !info.getColumn().equals("manager_id"));
         List<User> userList = userMapper.selectList(queryWrapper);
         userList.forEach(System.out::println);
      }
      
条件构造器中condition的作用
  • wrapper中的方法重载,使用到condition,如(eq(boolean condition, R column, Object val)),将判空的条件添加到condition,condition就是设置可变参数设置是否为空
创建条件构造器时传入实体对象
  •     @Test
       public void selectByWrapperEntity() {
          User whereUser = new User();
          whereUser.setName("刘红雨");
          whereUser.setAge(32);
          QueryWrapper<User> queryWrapper = new QueryWrapper<>(whereUser);
    //    queryWrapper.like("name","雨").lt("age",40);
          List<User> userList = userMapper.selectList(queryWrapper);
          userList.forEach(System.out::println);
       }
    
  • 注意 entity和like之类的不能同时使用,如果需要like,模糊查询,只需要在属性上加上@TableField(condition=SqlCondition.LIKE) ,SqlCondition也是可以直接写的,

    @TableField(condition = SqlCondition.LIKE)
    private String name;// 姓名
    @TableField(condition = "%s&lt;#{%s}")
    private Integer age;// 年龄
    
allEq用法
  • allEq(Map<R, V> params)
    allEq(Map<R, V> params, boolean null2IsNull)
    allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
    

    全部eq(或个别isNull)

    个别参数说明:

    params : key为数据库字段名,value为字段值
    null2IsNull : 为true则在mapvaluenull时调用 isNull 方法,为false时则忽略valuenull

  • allEq(BiPredicate<R, V> filter, Map<R, V> params)
    allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
    allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) 
    

    个别参数说明:

    filter : 过滤函数,是否允许字段传入比对条件中
    paramsnull2IsNull : 同上

    @Test
       public void selectByWrapperAllEq() {
          QueryWrapper<User> queryWrapper = new QueryWrapper<>();
          Map<String,Object> params = new HashMap<>();
          params.put("name","王天风");
          params.put("age",25);
    //    queryWrapper.allEq(params);
          queryWrapper.allEq((k,v)->!k.equals("name"),params);
          List<User> userList = userMapper.selectList(queryWrapper);
          userList.forEach(System.out::println);
       }
    
通用Mapper
  • 其他以条件构造器为参数的查询方法

  • // 根据 Wrapper 条件,查询全部记录
    List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    
  • /* {0}可变参数
     */
    @Test
    public void selectByWrapperMaps2() {
       QueryWrapper<User> queryWrapper = new QueryWrapper<>();
       queryWrapper.select("avg(age) avg_age","min(age) min_age","max(age) max_age").groupBy("manager_id").having("sum(age)<{0}",500);
       List<Map<String,Object>> userList = userMapper.selectMaps(queryWrapper);
       userList.forEach(System.out::println);
    }
    
  • // 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
    List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    
  • // 根据 Wrapper 条件,查询总记录数
    Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    
  • // 根据 entity 条件,查询一条记录
    T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
    
Lambda条件构造器
  • 好处:确保数据列表的准确性,防误触功能。

  • @Test
       public void selectLambda() {
    //    LambdaQueryWrapper<Object> lambda = new QueryWrapper<>().lambda();//第一种创建
    //    LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();//第二张
          LambdaQueryWrapper<User> lambdaQuery = Wrappers.<User>lambdaQuery();
          lambdaQuery.like(User::getName,"雨").lt(User::getAge,40);//where name like "雨"
          List<User> userList = userMapper.selectList(lambdaQuery);
          userList.forEach(System.out::println);
       }
    

自定义SQL

  • 通过注解的方式

    • @Test
      public void selectMy() {
         LambdaQueryWrapper<User> lambdaQuery = Wrappers.<User>lambdaQuery();
         lambdaQuery.like(User::getName,"王").and(lqw->lqw.lt(User::getAge,40).or().isNotNull(User::getEmail));
         List<User> userList = userMapper.selectAll(lambdaQuery);
         userList.forEach(System.out::println);
      }
       @Select("select * from user ${ew.customSqlSegment}")
          List<User> selectAll(@Param(Constants.WRAPPER)Wrapper<User> wrapper);
      
  • 通过Mapper的形式(xml配置)

    • 首先需要在application配置文件中添加上mapper文件的映射路径

      • mybatis-plus:
          mapper-locations: classpath*:mybatis/mapper/*.xml
        
    • 其次编写mapper文件,{ew.customSqlSegment}查询不需要加上where,会自动判断

      • <?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.mp.dao.UserMapper">
          <select id="selectAll" resultType="com.mp.entity.User">
            select * from user ${ew.customSqlSegment}
          </select>
        </mapper>
        

MyBatis分页介绍

  • Mybatis逻辑分页:Mybatis分页,内存分页,把符合条件的数据到内存中,返回你所需要的,数据量过大,产生问题:消耗内存;查询数据慢。

MP分页插件实现物理分页

  • 配置插件,配置PaginationInterceptor

    • /**
       * @Description
       * @Author tangmf
       * @Date 2020/1/14 10:47
       */
      @Configuration
      public class MyBatisPlusConfig {
         @Bean // 加入到spring容器管理
         public PaginationInterceptor paginationInterceptor() {
            return new PaginationInterceptor();
         }
      }
      
  • 底层方法

    • // 根据 entity 条件,查询全部记录(并翻页)返回实体
      IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
      // 根据 Wrapper 条件,查询全部记录(并翻页) 返回Map
      IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
      
    • @Test
      	public void selectPage() {
      		QueryWrapper<User> queryWrapper = new QueryWrapper<>();//第一种
      		queryWrapper.ge("age",26);
      		Page<User> userPage = new Page<>(1, 2);
      		/*IPage<User> iPage = userMapper.selectPage(userPage, queryWrapper);
      		System.out.println("总页数:"+iPage.getPages());
      		System.out.println("总记录数:"+iPage.getTotal());
      		List<User> userList = iPage.getRecords();
      		userList.forEach(System.out::println);*/
      		IPage<Map<String,Object>> iPage = userMapper.selectMapsPage(userPage, queryWrapper);
      		System.out.println("总页数:"+iPage.getPages());
      		System.out.println("总记录数:"+iPage.getTotal());
      		List<Map<String,Object>> userList = iPage.getRecords();
      		userList.forEach(System.out::println);
      	}
      
    • 不需要总记录数,只需要记录

      • public Page(long current, long size, boolean isSearchCount) {
            this(current, size, 0, isSearchCount);
        }
        
    • 自定义分页语句,写在UserMapper中,多表查询类似,xml中写多表查询即可

      • IPage<User> selectUserPage(Page<User> userPage,@Param(Constants.WRAPPER)Wrapper<User> wrapper);
        
      • @Test
        public void selectMyPage() {
           QueryWrapper<User> queryWrapper = new QueryWrapper<>();//第一种
           queryWrapper.ge("age",26);
           Page<User> userPage = new Page<>(1, 2,false);
           //调用xml中的
           IPage<User> iPage = userMapper.selectUserPage(userPage, queryWrapper);
           System.out.println("总页数:"+iPage.getPages());
           System.out.println("总记录数:"+iPage.getTotal());
           List<User> userList = iPage.getRecords();
           userList.forEach(System.out::println);
        }
        

更新(Update)

  • 根据id更新

    • // 根据 ID 修改
      int updateById(@Param(Constants.ENTITY) T entity);
      
    • @Test
      public void updateById() {
         User user = new User();
         user.setId(1088248166370832385L);
         user.setAge(26);
         user.setEmail("wtf2@baomidou.com");
         int rows = userMapper.updateById(user);
         System.out.println("影响记录数:" + rows);
      }
      
  • 以条件构造器作为参数的更新方法

    • 主要使用的是UpdateWrapper。

    • // 根据 whereEntity 条件,更新记录,实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
      int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
      
    • 主要运用于更新实体

    • @Test
      public void updateByWrapper() {
         UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
         updateWrapper.eq("name", "李艺伟").eq("age", 28);
         User user = new User();
         user.setEmail("lyw2@baomidou.com");
         user.setAge(29);
         int rows = userMapper.update(user, updateWrapper);
         System.out.println("影响记录数:" + rows);
      }
      
  • 条件构造器中set方法使用

    • 更新少量字段使用

    • @Test // 只需要更新一个属性,不需要去创建对象
      	public void updateByWrapper2() {
      		UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
      		updateWrapper.eq("name", "李艺伟").eq("age", 29).set("age", "30");
      		int rows = userMapper.update(null, updateWrapper);
      		System.out.println("影响记录数:" + rows);
      	}
      
  • lambda方式使用

    • LambdaUpdateWrapper,主要用于防误写功能,属性名不需要自己书写

    • @Test // Lambda方式 加入防误写功能
      public void updateByWrapperLambda() {
         LambdaUpdateWrapper<User> lambdaUpdate = Wrappers.<User> lambdaUpdate();
         lambdaUpdate.eq(User::getName, "李艺伟").eq(User::getAge, 30).set(User::getAge, 31);
         int rows = userMapper.update(null, lambdaUpdate);
         System.out.println("影响记录数:" + rows);
      }
      
    • LambdaUpdateChainWrapper,直接使用,不需要创建对象

    • @Test
      public void updateByWrapperLambdaChain() {
          boolean update = new LambdaUpdateChainWrapper<User>(userMapper).eq(User::getName, "李艺伟")
                  .eq(User::getAge, 31).set(User::getAge, 32).update();
          System.out.println("是否成功:" + update);
      }
      

删除(Delete)

  • 根据id删除的方法

    • @Test
      public void deleteById() {
         int rows = userMapper.deleteById(0L);
         System.out.println("删除条数:" + rows);
      }
      
  • 其他普通删除方法

    • map删除,为where条件

    • @Test
      public void deleteByMap() {
         HashMap<String, Object> columnMap = new HashMap<>();
         columnMap.put("name","王天风1");
         columnMap.put("age",26);
         int rows = userMapper.deleteByMap(columnMap);
         System.out.println("删除条数:" + rows);
      }
      
    • 删除多个

    • // 删除(根据ID 批量删除)
      int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
      @Test
      	public void deleteByIds() {
      		int rows = userMapper.deleteBatchIds(Arrays.asList(1094590409767661571L, 1094590409767661572L));
      		System.out.println("删除条数:" + rows);
      	}
      
  • 以条件构造器为参数的删除方法

    • wrapper设置删除的where条件

    • @Test
      public void deleteByWrapper() {
         LambdaQueryWrapper<User> lambdaQuery = Wrappers.<User> lambdaQuery();
         lambdaQuery.eq(User::getAge, 27).or().gt(User::getAge, 41);
         int rows = userMapper.delete(lambdaQuery);
         System.out.println("删除条数:" + rows);
      }
      

ActiveRecord模式

AR探索

  • AR模式简介:领域模型模式,特点是一个模型类对应关系型数据库中的一个表,模型类的实例对应表中的一行记录。简单来说,通过实体类对象,直接进行表的增删改查操作,方便开发人员的开发。

  • 要求:

    • 实体类需要继承Model类

    • 必须存在对应的原始mapper并继承baseMapper并且可以使用的前提下

    • @EqualsAndHashCode(callSuper = false)
      public class User extends Model<User> {}
      

MP中AR模式的实现

  • 不需要在注入UserMapper就可以完成操作。增删改查方法会调用model类中的各种方法。有些方法,需要看原型去了解其使用与wrapper中的有一些的区别。

  • @Test
    public void insert() {
       User user = new User();
       user.setName("向北");
       user.setAge(26);
       user.setEmail("xb@baomidou.com");
       user.setManagerId(1088248166370832385L);
       user.setCreateTime(LocalDateTime.now());
       boolean insert = user.insert();
       System.out.println("是否成功:" + insert);
    }
    @Test
    	public void selectById() {
    		User user = new User();
    		User user1 = user.selectById(0L);
    		System.out.println(user1);
    		System.out.println(user1 == user);
    	}
    

主键策略

  • MP支持的主键策略介绍,主要使用到的是IdType来设置主键

  • 注意:局部主键策略优先级高于全局主键策略

  • 局部主键策略实现

    • 需要设置数据库列自增

      • alter TABLE `user` CHANGE COLUMN id id BIGINT(20) auto_increment;
        
    • 属性使用@TableId(type = IdType.AUTO)

  • 全局主键策略实现

    • 在application.yml配置文件中使用,主要是因为需要多个实体的主键策略使用

    • #配置全局主键策略
      global-config:
        db-config:
          id-type: id_worker
      

MP配置

  • 基本配置,运用官方帮助文档进行设置

  • 进阶配置

    • 在 update,insert,delete,select 的时候的字段验证策略 目前没有默认值,等 {@link #fieldStrategy} 完全去除掉,会给个默认值 NOT_NULL 没配则按 {@link #fieldStrategy} 为准

    • field-strategy: ignored
      
    • 表名前缀

      • #配置全局主键策略
        global-config:
          db-config:
            id-type: id_worker
            table-prefix: mp_
        
    • tableUnderline表名、是否使用下划线命名,默认数据库表使用下划线命名

  • DB策略配置

通用Service

  • 基本方法

    • UserService extends IService<T>
      UserServiceImpl extendsServiceImpl<M extends BaseMapper<T>, T>
      UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService
      操作实体,操作Mapper
      
    • 特殊情况

    • @Test
      public void getOne() {
         User user = userService.getOne(Wrappers.<User> lambdaQuery().gt(User::getAge, 25),false);
         System.out.println(user);
      }
      
  • 批量操作方法(Batch)

    •     @Test
         public void Batch() {
            User user1 = new User();
            user1.setName("徐丽1");
            user1.setAge(28);
      
            User user2 = new User();
            user2.setId(1094592041087729672L);
            user2.setName("徐2");
            user2.setAge(29);
            List<User> userList = Arrays.asList(user1, user2);
      //    boolean b = userService.saveBatch(userList);
              boolean b = userService.saveOrUpdateBatch(userList);
              System.out.println("是否成功:" + b);
         }
      
  • 链式调用方法(Lambda)

    • @Test//查询
      public void chain() {
         List<User> userList = userService.lambdaQuery().ge(User::getAge, 25).like(User::getName, "雨").list();
         userList.forEach(System.out::println);
      }
      
      @Test//更新
      public void chain1() {
             boolean update = userService.lambdaUpdate().eq(User::getAge, 25).set(User::getAge, 26)
                     .update();
             System.out.println(update);
      }
      @Test //删除
          public void chain2() {
              boolean update = userService.lambdaUpdate().eq(User::getAge, 29).remove();
              System.out.println(update);
          }
      

版权声明:本文为qq_39031310原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_39031310/article/details/105156203