Mybatis-Plus(尚庭公寓)

Mybatis-Plus

💹偷懒用的, 简介 | MyBatis-Plus (baomidou.com)

1.boot中集成

  1. 先导入依赖
  2. 一般在model模块中实体类头顶,需要加入注解 @Data @TableName(“user”), ⭕⭕⭕有点类似于JPA,
  3. 主键注解 @TableId(value = “id”, type = IdType.AUTO)
  4. 普通字段注解 @TableField(“name”)

2.传统的mapper和Mapper.xml编写方式

public interface AdjustSalaryMapper {   //以下mapper接口 中的方法提供给service层调用
    int deleteByPrimaryKey(Integer id);
    int insert(AdjustSalary record);
    int insertSelective(AdjustSalary record);
    AdjustSalary selectByPrimaryKey(Integer id);
    int updateByPrimaryKeySelective(AdjustSalary record);
    int updateByPrimaryKey(AdjustSalary record);
    List<AdjustSalary> getAllAdjustSalary();
}

//以下是mapper.xml写具体的sql
<?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="org.javaboy.vhr.mapper.AdjustSalaryMapper" >
  <resultMap id="BaseResultMap" type="org.javaboy.vhr.model.AdjustSalary" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="eid" property="eid" jdbcType="INTEGER" />
    <result column="asDate" property="asdate" jdbcType="DATE" />
    <result column="beforeSalary" property="beforesalary" jdbcType="INTEGER" />
    <result column="afterSalary" property="aftersalary" jdbcType="INTEGER" />
    <result column="reason" property="reason" jdbcType="VARCHAR" />
    <result column="remark" property="remark" jdbcType="VARCHAR" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, eid, asDate, beforeSalary, afterSalary, reason, remark
  </sql>

  <resultMap id="adjustSalaWithNname" type="org.javaboy.vhr.model.AdjustSalary" extends="BaseResultMap">
    <association property="employee" javaType="org.javaboy.vhr.model.Employee">
      <result column="ename" property="name" jdbcType="VARCHAR"/>
    </association>
  </resultMap>

    <!--  查询所有工资调整记录-->
    <select id="getAllAdjustSalary" resultMap="adjustSalaWithNname">
        select a.* ,e.`name` as ename	 from adjustsalary a left join employee e on(e.id=a.eid)
    </select>


3.❗❗❗MP的通用Mapper接口

mybaties没有的,MP最大的特点就是提供了这些通用的crud,不用手写。

第一步

创建 UserMapper接口,并继承由Mybatis Plus提供的 BaseMapper接口,如下

@Mapper  //记得加@mapper
public interface UserMapper extends BaseMapper<User> {  //记得继承于MP的 💹BaseMapper <xxxx>
    
}

偷懒方法:若mapper interface太多,可用扫描的方式去进行统一管理,不用每一个 都加 注解@mapper

第二步:测试UserMapper

💹Users是数据库中的一个表,也是Model中的一个实体类

SpringBootTest
class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectList() {
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }

    @Test
    public void testSelectById() {
        User user = userMapper.selectById(1); //💹userMapper.selectById(1) 中selectById()这个方法是MP自动写好的
        System.out.println(user);
    }

    @Test
    public void testInsert() {
        User user = new User();
        user.setName("zhangsan");
        user.setAge(11);
        user.setEmail("test@test.com");
        userMapper.insert(user);
    }

    @Test
    public void testUpdateById() {
        User user = userMapper.selectById(1);
        user.setName("xiaoming");
        userMapper.updateById(user);
    }
    
    @Test
    public void testDeleteById() {
        userMapper.deleteById(1);  // .deleteById(1)也是 MP自带的
    }
}

4.❗❗❗通用Service

💹通用Service进一步封装了通用Mapper的CRUD方法
这个也是MP提供的通用 service层,例如saveOrUpdatesaveBatch等高级方法。

通用mapper的crud的方法名更贴近数据库,eg: select、 insert
通用service的crud的方法名更贴近业务 eg: get 、save

第一步创建service接口

public interface UserService extends IService<User> {  //IService<User>是💹 MP特有的, 💹泛型接口
}

第二步创建service实现类 impl

//@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
                                  //extends ServiceImpl<UserMapper, User> 注意他还继承这个类
                                  //ServiceImpl<UserMapper, User>里面实现了IService<User>里面的所有接口,也是泛型
}

第三步测试通用service

@SpringBootTest
class UserServiceImplTest {


    @Autowired
    private UserService userService;

    @Test
    public void testSaveOrUpdate() {
        User user1 = userService.getById(2); //💹getById(x)是通用方法
        user1.setName("xiaohu");

        User user2 = new User();
        user2.setName("lisi");
        user2.setAge(27);
        user2.setEmail("lisi@email.com");
        
        userService.saveOrUpdate(user1);  //💹如果id不为空,这插入,如果id为空,这更新数据库记录
        userService.saveOrUpdate(user2);
    }

    @Test
    public void testSaveBatch() {
        User user1 = new User();
        user1.setName("dongdong");
        user1.setAge(49);
        user1.setEmail("dongdong@email.com");

        User user2 = new User();
        user2.setName("nannan");
        user2.setAge(29);
        user2.setEmail("nannan@email.com");

        List<User> users = List.of(user1, user2);
        userService.saveBatch(users);   //💹saveBatch保存一组user,本质上是insert一组数据在数据库中
    }
}
image-20240614151448502

这个方法本身也是调用 mapper层的方法,⭕本质上就是 mapper层的 selectById () 方法,只是名字不一样而已

image-20240614151532125

5.条件构造器Querywrapper

image-20240614190742138
⭕通用的mapper和service是只有 selectById()这些方法是无法满足使用需求的,所以需要构造器

条件构造器用于构造复杂的查询条件,例如获取name='zhangsan'的用户。MyBatis Plus共提供了两类构造器,分别是QueryWrapperUpdateWrapper。其中QueryWrapper主要用于查询、删除操作,UpdateWrapper主要用于更新操作,下面通过几个案例学习条件构造器的基础用法。

  • AbstractWrapper:这是一个抽象基类,提供了所有 Wrapper 类共有的方法和属性。它定义了条件构造的基本逻辑,包括字段(column)、值(value)、操作符(condition)等。💹所有的 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper 都继承自 AbstractWrapper。
  • 💹QueryWrapper:专门用于构造查询条件,支持基本的等于、不等于、大于、小于等各种常见操作。它允许你以💹链式调用的方式添加多个查询条件,并且可以组合使用 andor 逻辑。
  • 💹UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。与 QueryWrapper 类似,它也支持链式调用和逻辑组合。使用 UpdateWrapper 可以在不创建实体对象的情况下,直接设置更新字段和条件。
  • LambdaQueryWrapper:这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。
  • LambdaUpdateWrapper:类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题

缺点

  1. RPC 调用中的 Wrapper:不支持也不赞成在 RPC 调用中传输 Wrapper 对象。Wrapper 对象通常包含大量信息,不适合作为传输对象。正确的做法是定义一个 DTO(数据传输对象)进行传输,然后在被调用方根据 DTO 执行相应的操作。
  2. 维护性:避免在 Controller 层使用 Map 接收值,💹这种做法虽然开发时方便,但会给后续的维护带来困难。
  3. 问题反馈:不接受任何关于 RPC 传输 Wrapper 报错相关的 issue 或 pr。
  4. 安全性QueryWrapper UpdateWrapper 字段部分,如有允许 前端传入 SQL 片段 这可能会导致 SQL 注入风险 需要校验,更多查看 预防安全漏洞
❗主要使用QueryWrapper 和 UpdateWrapper 这两个条件构造器

第一步:创建WrapperTest测试类

@SpringBootTest
public class WrapperTest {   💹💹💹//这里相当于在controller层,因为下面是调用userService层

    @Autowired
    private UserService userService;

    @Test
    public void testQueryWrapper() {

        //查询name=Tom的所有用户
        QueryWrapper<User> queryWrapper1 = new QueryWrapper<>();   //💹QueryWrapper<User>中user也是泛型
        queryWrapper1.eq("name", "Tom");                           //💹第一个是数据库字段,第二个是 字段值
        List<User> list = userService.list(querywrapper);
        //💹userService.list(传入一个querywrapper对象), .list这个方法是Mybatis-plus的特有的通用的service方法
       
        
        //查询邮箱域名为baomidou.com的所有用户
        QueryWrapper<User> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.like("email", "baomidou.com");  //💹相当于sql中 ‘% baomindou.com %’  匹配xxbaomindou.comxx

        //查询所有用户信息并按照age字段降序排序
        QueryWrapper<User> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.orderByDesc("age");
        List<User> list = userService.list(queryWrapper3);
        
        //查询age介于[20,30]的所有用户
        QueryWrapper<User> queryWrapper4 = new QueryWrapper<>();
        queryWrapper4.between("age", 20, 30);
        List<User> list = userService.list(queryWrapper4);
        
        //查询age小于20 或 大于30的用户
        QueryWrapper<User> queryWrapper5 = new QueryWrapper<>();
        queryWrapper5.lt("age", 20).or().gt("age", 30);  //💹注意中间有个or
        List<User> list = userService.list(queryWrapper5);

        //邮箱域名为baomidou.com且年龄小于30或大于40且的用户
        //where email like "%baomidou.coms' and (age <30 or age >40)
        QueryWrapper<User> queryWrapper6 = new QueryWrapper<>();
        queryWrapper6.like("email", "baomidou.com").and(wrapper -> wrapper.lt("age", 30).or().gt("age", 40));

        List<User> list = userService.list(queryWrapper6);
        list.forEach(System.out::println);
    }

    @Test
    public void testUpdateWrapper() {

        //将name=Tom的用户的email改为Tom@baobidou.com
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("name", "Tom");
        updateWrapper.set("email", "Tom@baobidou.com");

        userService.update(updateWrapper);
    }
}
allEq
// 设置所有字段的相等条件,如果字段值为null,则根据null2IsNull参数决定是否设置为IS NULL
allEq(Map<String, Object> params)
allEq(Map<String, Object> params, boolean null2IsNull)
allEq(boolean condition, Map<String, Object> params, boolean null2IsNull)

// 设置所有字段的相等条件,通过filter过滤器决定哪些字段应该被包含,如果字段值为null,则根据null2IsNull参数决定是否设置为IS NULL
allEq(BiPredicate<String, Object> filter, Map<String, Object> params)
allEq(BiPredicate<String, Object> filter, Map<String, Object> params, boolean null2IsNull)
allEq(boolean condition, BiPredicate<String, Object> filter, Map<String, Object> params, boolean null2IsNull)

eg:

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.allEq(Map.of("id", 1, "name", "老王", "age", null));
eq
// 设置指定字段的相等条件
eq(R column, Object val)

// 根据条件设置指定字段的相等条件
eq(boolean condition, R column, Object val)
  • column:数据库字段名或使用 Lambda 表达式的字段名。
  • val:与字段名对应的值。
  • condition:一个布尔值,用于控制是否应用这个相等条件。

eg:

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "老王");
image-20240614191329488
like模糊查询
  • notLike
  • likeLeft
  • likeRight
  • notLikeLeft
  • notLikeRight

后序用到再去官网查阅

条件构造器 | MyBatis-Plus (baomidou.com)

6.条件构造器Updatewrapper

主要关注 where 和 set

image-20240616131502577
        //将name=Tom的用户的email改为Tom@baobidou.com
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("name", "Tom").set("email", "Tom@baobidou.com")//💹eq就是where语句    set就是set语句
        userService.update (updatewrapper);
        //标准sql  UPDATE table_name  SET column1 = value1, column2 = value2 WHERE condition;

7.分页插件

  1. 先创建一个配置类,具体看官网

  2. 构造分页对象 Page

    IPage<T> page = new Page<>(current, size); //💹只传入两个参数,current和size
    
    image-20240616133739663
  3. 分页查询

    Mybatis Plus的BaseMapperServiceImpl均提供了常用的分页查询的方法,例如:

    • 1.通用BaseMapper的分页查询:

      IPage<T> selectPage(IPage<T> page,Wrapper<T> queryWrapper); 
      
      
      
          //通用Mapper分页查询
          @Test
          public void testPageMapper() {
              IPage<User> page = new Page<>(2, 3);
              IPage<User> userPage = 💹userMapper.selectPage(page, null) 
              💹//这个方法是MP中通用usermapper的selectPage()
              userPage.getRecords().forEach(System.out::println);
          }
      
      
    • 2.通用ServiceImpl的分页查询:

          // 无条件分页查询
          IPage<T> page(IPage<T> page);
          // 条件分页查询
          IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
      
          //通用Service分页查询
          @Test
          public void testPageService() {
              Page<User> page = new Page<>(2, 3);  //💹我想查询第2页,每页有3条数据记录
              Page<User> userPage = 💹userService.page(page); //userService.page是MP提供的接口
              userPage.getRecords().forEach(System.out::println); //record就是那一页的 每一条的所有记录
              
          }
      
      image-20240616135640380
    • 3.自定义Mapper

      💹MP会提供通用mapper,但是自己也可以定义,自己定义的就回到了mybaties时代了
      

      对于自定义SQL,也可以十分方便的完成分页查询,如下

      ①Mapper接口:

      IPage<UserVo> selectPageVo(IPage<?> page, Integer state);
      
      image-20240616144048877

      ②编写Mapper.xml

      创建resources/mapper/UserMapper.xml文件,内容如下

      //💹这里面只负责查询所有,不用关注分页
      
      <?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.atguigu.hellomp.mapper.UserMapper">
          <select id="selectUserPage" resultType="com.atguigu.hellomp.entity.User">
              select *         
              from user
          </select>   
      </mapper>
      

      注意Mapper.xml中的SQL只需实现查询list的逻辑即可,无需关注分页的逻辑。

      public void testCustomMapper() {
              IPage<User> page = new Page<>(2, 3);
              IPage<User> userPage = 💹userMapper.selectUserPage(page); 
      	   //💹selectUserPage这个方法是直接定义的,不是MP自带的
              userPage.getRecords().forEach(System.out::println);
          }
      

8.Mybatis X 插件

❗❗❗类似于以前用的 mybatis-generator-core-1.3.1代码生成器

MyBatis Plus提供了一个IDEA插件——MybatisX,使用它可根据数据库快速生成EntityMapperMapper.xmlServiceServiceImpl等代码,使用户更专注于业务。

  1. 先安装插件 (在IDEA插件市场搜索MyBatisX

  2. 配置数据库连接

  3. 生成代码

    首先将之前编写的UserUserMapperUserServcieUserServiceImpl全部删除,然后按照下图指示使用插件生成代码
    image-20240616162017619

SpringBoot中MybatisX插件的简单使用教程(超详细!!)-CSDN博客

9.偷懒方法

在上面的示例中,我们定义了一个UserMapper接口,并使用注解标注了查询、插入、更新和删除方法。通过这种方式,我们可以省去编写XML配置文件的步骤,使代码更加简洁和易于理解。

@Mapper
public interface UserMapper {
    @Select("SELECT * FROM user WHERE id = #{id}")  // 直接在这里写select 
    User getUserById(@Param("id") int id);

    @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
    void addUser(User user);

    @Update("UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}")
    void updateUser(User user);

    @Delete("DELETE FROM user WHERE id = #{id}")
    void deleteUser(@Param("id") int id);
}

  • 17
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值