MyBatis-Plus(实用篇)

文章目录

  • 一、基础组件(接口和实现类)
    • 1、BaseMapper\
    • 2、IService\
    • 3、链式查询与修改
    • 4、调用Service层操作数据
  • 二、常用注解
    • 1、@TableName
    • 2、@TableId
    • 3、@TbaleField
    • 4、@TableLogic
  • 三、条件构造器
    • 1、wapper介绍
    • 2、构造器常用方法
    • 3、组装条件示例
    • 4、自定义分页
    • 5、IPage的泛型转换(entity转换为vo)
  • 四、MyBatisX插件
    • 1、生成逆向工程
    • 2、快速生成CRUD

一、基础组件(接口和实现类)

简介

  • MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具
  • 在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生

1、BaseMapper

  • BaseMapper是MyBatis-Plus提供的模板mapper,其中包含了基本的CRUD方法,泛型为操作的实体类型
  • Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
  • BaseMapper接口,增删改返回影响数据条数的Integer

MyBatis-Plus(实用篇)_第1张图片

BaseMapper中提供的CRUD方法

  • 增加:insert

在这里插入图片描述

  • 删除:delete

MyBatis-Plus(实用篇)_第2张图片

  • 修改:update
  • update方法:entity实体对象某属性为null,则不会修改此属性

MyBatis-Plus(实用篇)_第3张图片

  • 查询:select

MyBatis-Plus(实用篇)_第4张图片

  • selectObjs方法:只返回第一个字段的值
  • selectPage方法:分页需要添加MybatisPlusInterceptor插件,否则不生效

MyBatis-Plus(实用篇)_第5张图片

MybatisPlusInterceptor分页插件

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //注意使用哪种数据库
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

2、IService

  • 封装IService接口,进一步封装CRUD采用get查询单行、remove删除、list查询集合、page分页前缀命名方式
  • IService接口,增删改返回是否操作成功的boolean
  • 泛型 T 为任意实体对象

MyBatis-Plus(实用篇)_第6张图片

IService中提供的CRUD方法

  • 增加:save

MyBatis-Plus(实用篇)_第7张图片

  • 删除:remove

MyBatis-Plus(实用篇)_第8张图片

  • 修改:update

MyBatis-Plus(实用篇)_第9张图片

  • 新增或修改:主键存在则根据主键修改,主键不存在则新增

在这里插入图片描述

  • 查询:单个get,集合list
  • getOne方法,多个抛出异常,boolean throwEx = false 则获取第一条数据

MyBatis-Plus(实用篇)_第10张图片
MyBatis-Plus(实用篇)_第11张图片

  • 查询记录数:count

MyBatis-Plus(实用篇)_第12张图片

  • 分页查询:page

MyBatis-Plus(实用篇)_第13张图片
MyBatis-Plus(实用篇)_第14张图片

  • 集合查询:list
  • listObjs方法,可以将查询结果T类型转换成V类型返回List

MyBatis-Plus(实用篇)_第15张图片

3、链式查询与修改

IService接口中提供

  • 链式查询:可以串着写多个条件
    • .one()结尾:查询单条数据
    • .list()结尾:查询多条数据
    • .count()结尾:查询记录数

MyBatis-Plus(实用篇)_第16张图片

 @Test
 public void test1(){
 	 // 单个查询,多个报错
     User user = userService.lambdaQuery().eq(User::getName, "Tom").one();
	 // 集合查询
     List<User> userList = userService.lambdaQuery().like(User::getName, "J").eq(User::getAge,20).list();
     // 记录数查询
     Integer count = userService.lambdaQuery().like(User::getAge, 20).select(User::getName, User::getAge).count();
  }
  • 链式修改:可以串着写多个条件
    • .update()结尾:修改set的字段
    • .update(entity)结尾:修改entity数据的字段
    • .remove()结尾:删除数据

MyBatis-Plus(实用篇)_第17张图片

  @Test
  public void test2() {
	  // set修改某些属性
      userService.lambdaUpdate().eq(User::getName, "Tom").set(User::getId, 110).set(User::getAge, 15).update();
      // 修改整个对象
      User user = new User();
      user.setId(110L);
      user.setAge(15);
      userService.lambdaUpdate().eq(User::getName, "Tom").update(user);
      // 根据名称删除
      userService.lambdaUpdate().eq(User::getName, "Jack").remove();
   }

4、调用Service层操作数据

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

二、常用注解

1、@TableName

  • 在实体类类型上添加@TableName(“t_user”),标识实体类对应的表
  • 不加注解,默认驼峰转下划线则是表明,如实体OrderInfo,则默认对应表名order_info
@Data
@TableName("t_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
  • 为实体类所对应的表名设置默认的前缀,那么就不需要在每个实体类上通过@TableName标识实体类对应的表
mybatis-plus:
  global-config:
    db-config:
      # 设置实体类所对应的表的统一前缀
      table-prefix: t_

2、@TableId

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

@TableId的value属性

  • 不加注解,默认情况Long id就是主键
  • 如果想其他字段作为主键,则添加@TableId
  • 如果想其他字段作为主键,且实体与数据库字段不一致,则添加@TableId(value = “tid”)
@Data
public class User {
    @TableId(value = "tid")
    private Long uid;
    private String name;
    private Integer age;
    private String email;
}

@TableId的type属性

常用主键策略:

描述
IdType.ASSIGN_ID(默认) 基于雪花算法的策略生成数据id,与数据库id是否设置自增无关
IdType.AUTO 使用数据库的自增策略,注意,该类型请确保数据库设置了id自增
@Data
public class User {
    @TableId(type = IdType.AUTO)
    private Long uid;
    private String name;
    private Integer age;
    private String email;
}

3、@TbaleField

  • 实体字段不满足数据库下划线转驼峰的解决方法(实体-name,数据库-username)
public class User {
    private Long id;
    @TableField("username")
    private String name;
    private Integer age;
    private String email;
}

4、@TableLogic

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

实现逻辑删除

  • 数据库中创建逻辑删除状态列,设置默认值为0

MyBatis-Plus(实用篇)_第18张图片

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

MyBatis-Plus(实用篇)_第19张图片

  • 测试删除功能,真正执行的是修改
public void testDeleteById(){
    int result = userMapper.deleteById(1527472864163348482L);
    System.out.println(result > 0 ? "删除成功!" : "删除失败!");
    System.out.println("受影响的行数为:" + result);
}

MyBatis-Plus(实用篇)_第20张图片

  • 此时执行查询方法,查询的结果为自动添加条件is_deleted=0
public void testSelectList(){
    List<User> users = userMapper.selectList(null);
}

MyBatis-Plus(实用篇)_第21张图片

三、条件构造器

1、wapper介绍

MyBatis-Plus(实用篇)_第22张图片

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

2、构造器常用方法

函数名 说明 说明/例子
eq 等于= 例:eq(“name”,“zhangsan”) —> name = ‘zhangsan’
ne 不等于<> 例:ne(“name”,“zhangsan”) —> name <> ‘zhangsan’
gt 大于> 例:gt(“age”,18) —> age > 18
ge 大于等于>= 例:ge(“age”,18) —> age >= 18
lt 小于< 例:lt(“age”,18) —> age < 18
le 小于等于<= 例:le(“age”,18) —> age <= 18
between between 值1 and 值2 例:between(“age”,10,20) —> age between 10 and 20
notBetween not between 值1 and 值2 例:notBetween(“age”,10,20) —> age not between 10 and 20
like like ‘%值%’ 例:like(“name”,“强”) —> name like ‘%强%’
notLike not like ‘%值%’ 例:notLike(“name”,“强”) —> name not like ‘%强%’
likeLeft like ‘%值’ 例:like(“name”,“飞”) —> name like ‘%强’
likeRight like ‘值%’ 例:like(“name”,“王”) —> name like ‘王%’
isNull 字段 is null 例:isNull(“emal”) —> email is null
isNotNull 字段 is not null 例:isNotNull(“emal”) —> email is not null
in 字段 in (值1,值2…) 例:in(“age”,{10,18,30}) —> age in (10,18,30)
notIn 字段 not in (值1,值2…) 例:notIn(“age”,{10,18,30}) —> age not in (10,18,30)
inSql 字段 in ( sql语句 ) inSql(“id”, “select id from table where name like ‘%J%’”)
—> id in (select id from table where name like ‘%J%’)
notInSql 字段 not in ( sql语句 ) notInSql(“id”, “select id from table where name like ‘%J%’”)
—> id not in (select id from table where name like ‘%J%’)
groupBy 分组 group by 字段,… 例:groupBy(“id”,“name”) —> group by id,name
orderBy 排序 ordery by 字段,… 例:orderBy(true,true,“id”,“name”) —> order by id asc,name asc
orderByAsc 升排序 order by 字段,… asc 例:orderByAsc(“id”,“name”) —> order by id,name
orderByDesc 降排序 order by 字段,… desc 例:orderByDesc(“id”,“name”) —> order by id desc,name desc
having having (sql语句) having(“sum(age) > {0}”,18) —> having sum(age) > 18
or 拼接or 例:eq(“id”,1).or().eq(“name”,“老王”) —> id =1 or name = ‘老王’
and and 嵌套 例:and(i -> i.eq(“name”,“李白”).ne(“status”,“活着”))
—> and (name = ’李白‘ and status <> ‘活着’)
apply 拼接sql 例:apply(“date_format(date_time,‘%Y-%m-%d’) = {0}”,“2002-08-08”)
—> date_fromat(date_time,‘%Y-%m-%d’) = ‘2008-08-08’
注意事项:动态入参对应{index}部分,直接写sql语句,有sql注入风险
last 拼接到sql的最后 例:last(“limit 5”)
注意事项:只能调用一次,多次调用以最后一次为准,有sql注入风险
exists 拼接exists (sql语句) 例:exists(“select id from table where age = 1”)
not exists 拼接not exists (sql语句) 例:not exists(“select id from table where age = 1”)
nested 正常嵌套 不带and和or 例:nested(i-> i.eq(“name”,“李华”).gt(“age”,20))
—> (name = “李华” and age > 20)

3、组装条件示例

条件的优先级

sql语句规则:and和or一起用,and优先级高

 /** 组装修改条件  将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改 **/
@Test
public void test01() {
    /*
        UPDATE t_user SET user_name=?, email=?
        age > ? AND user_name LIKE ? OR email IS NOT NULL
     */
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.gt("age", 20)
            .like("user_name", "a")
            .or()
            .isNotNull("email");
    User user = new User();
    user.setName("小明");
    user.setEmail("[email protected]");
    int result = userMapper.update(user, queryWrapper);
    System.out.println("result = " + result);
}

/** 条件优先级  将用户名中包含a并且(年龄大于20或邮箱为null)的用户信息修改 **/
@Test
public void test02() {
    // lambda中条件优先级
    /*
        UPDATE t_user SET user_name=?, email=?
        WHERE user_name LIKE ? AND (age > ? OR email IS NULL)
     */
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("user_name", "a")
            .and(i -> i.gt("age", 20).or().isNull("email"));
    User user = new User();
    user.setName("小红");
    user.setEmail("[email protected]");
    int result = userMapper.update(user, queryWrapper);
    System.out.println("result = " + result);
}

Lambda表达式

@Test
public void test3() {
    /*
        SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user
        WHERE user_name LIKE ? AND age <= ?
     */
    String username = "a";
    Integer ageBegin = null;
    Integer ageEnd = 30;
    //组装set子句
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    //避免使用字符串表示字段,防止运行时错误
    queryWrapper.like(StringUtils.isNotBlank(username), User::getName, username)
            .gt(ageBegin != null, User::getAge, ageBegin)
            .le(ageEnd != null, User::getAge, ageEnd);
    List<User> list = userMapper.selectList(queryWrapper);
    list.forEach(System.out::println);
}

@Test
public void test4() {
    /*
        UPDATE t_user SET user_name=?,email=?
        WHERE user_name LIKE ? AND (age > ? OR email IS NULL)
     */
    LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.like(User::getName, "a")
            //lambda表达式内的逻辑优先运算
            .and(i -> i.gt(User::getAge, 20).or().isNull(User::getEmail)); 
    updateWrapper.set(User::getName, "小黑").set(User::getEmail, "[email protected]");
    int result = userMapper.update(null, updateWrapper);
    System.out.println("result = " + result);
}

4、自定义分页

UserMapper中定义接口方法

  • page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位
/**
* 根据年龄查询用户列表,分页显示
*/
Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);

UserMapper.xml中编写SQL

<select id="selectPageVo" resultType="User">
    select id,username as name,age,email from t_user where age > #{age}
select>

测试方法

  • xml中没有分页语句,mybatisplus自动分页
@Test
public void testSelectPageVo(){ //设置分页参数
    Page<User> page = new Page<>(1, 5); 
    userMapper.selectPageVo(page, 20);
    //获取分页数据
    List<User> list = page.getRecords(); 
    list.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());
}

5、IPage的泛型转换(entity转换为vo)

// 分页查询
Page<UserEntity> userPage = super.lambdaQuery().page(new Page<>(request.getCurrent(), request.getSize()));
// entity转换为vo
IPage<UserVO> infoResPage = userPage.convert(item -> Convert.convert(UserVO.class, item));

四、MyBatisX插件

1、生成逆向工程

  • 找到我们需要生成的表点击右键

MyBatis-Plus(实用篇)_第23张图片

  • 填写完信息以后下一步

MyBatis-Plus(实用篇)_第24张图片

  • 继续填写信息

MyBatis-Plus(实用篇)_第25张图片

  • 结果展示

MyBatis-Plus(实用篇)_第26张图片

2、快速生成CRUD

MyBaitsX可以根据我们在Mapper接口中输入的方法名快速帮我们生成对应的sql语句

MyBatis-Plus(实用篇)_第27张图片

MyBatis-Plus(实用篇)_第28张图片

你可能感兴趣的:(mybatis,mybatis,java,mysql)