MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口

这篇具有很好参考价值的文章主要介绍了MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

MyBatisPlus详解系列文章:

MyBatisPlus详解(一)项目搭建、@TableName、@TableId、@TableField注解与常见配置

2 核心功能

2.1 条件构造器

2.1.1 Wrapper

在BaseMapper接口提供的相关方法中,除了以id作为where条件,还支持更加复杂的where条件,即条件构造器Wrapper

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

Wrapper是条件构造器的抽象类,其下有很多默认实现,继承关系如图:

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

Wrapper的子类AbstractWrapper提供了where中包含的所有条件构造方法:

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

而QueryWrapper在AbstractWrapper的基础上拓展了一个select方法,允许指定查询字段:

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

而UpdateWrapper在AbstractWrapper的基础上拓展了一个set方法,允许指定SQL中的SET部分:

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

2.1.2 QueryWrapper

使用QueryWrapper构建查询条件,例如:

  • select id, username, info, balance from t_user where id = 3 and username like '%o%' and balance >= 1000
@Test
public void testQueryWrapper() {
    // select id, username, info, balance from t_user
    // where id = 3 and username like '%o%' and balance >= 1000
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
            // 设置需要查询的字段
            .select("id", "username", "info", "balance")
            // id = 3
            .eq("id", 3)
            // like '%o%'
            .like("username", "o")
            // balance >= 1000
            .ge("balance", 1000);
    List<User> userList = userMapper.selectList(wrapper);
    userList.forEach(System.out::println);
}

执行以上单元测试结果如下:

==>  Preparing: SELECT id,username,info,balance FROM t_user WHERE (id = ? AND username LIKE ? AND balance >= ?)
==> Parameters: 3(Integer), %o%(String), 1000(Integer)
<==      Total: 1
User(id=3, username=Hope, password=null, phone=null, info={"age": 25, "intro": "上进青年", "gender": "male"}, status=null, balance=20000, createTime=null, updateTime=null)
  • update t_user set balance = 2000 where username = 'Jack'
@Test
void testUpdateByQueryWrapper() {
    // update t_user set balance = 2000 where username = 'Jack'
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
            // username = 'Jack'
            .eq("username", "Jack");
    // 2.更新数据
    User user = new User();
    user.setBalance(2000);
    userMapper.update(user, wrapper);
}

执行以上单元测试结果如下:

==>  Preparing: UPDATE t_user SET balance=? WHERE (username = ?)
==> Parameters: 2000(Integer), Jack(String)
<==    Updates: 0

2.1.3 UpdateWrapper

如上面的单元测试testUpdateByQueryWrapper()所示,update()方法更新时只能直接赋值,对于一些复杂的需求就难以实现,例如:

UPDATE t_user SET balance = balance - 200 WHERE id in (1, 2, 4);

SET语句的赋值结果是基于字段现有值的,这个时候就要利用UpdateWrapper中的setSql()方法了

@Test
void testUpdateWrapper() {
    List<Long> ids = Arrays.asList(1L, 2L, 4L);
    // 1.生成SQL
    UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
            // SET balance = balance - 200
            .setSql("balance = balance - 200")
            // WHERE id in (1, 2, 4)
            .in("id", ids);
    // 2.更新
    // 注意第一个参数为null,则会基于UpdateWrapper中的setSQL来更新
    userMapper.update(null, wrapper);
}

执行以上单元测试结果如下:

==>  Preparing: UPDATE t_user SET balance = balance - 200 WHERE (id IN (?,?,?))
==> Parameters: 1(Long), 2(Long), 4(Long)
<==    Updates: 2

2.1.4 LambdaQueryWrapper

无论是QueryWrapper还是UpdateWrapper,在构造条件的时候都需要写死字段名称,会出现字符串魔法值。这在编程规范中显然是不推荐的。

而要不写字段名,又能知道字段名,其中一种办法是基于变量的gettter方法结合反射技术。为此,MybatisPlus又提供了一套基于Lambda的Wrapper,包含两个:LambdaQueryWrapper和LambdaUpdateWrapper。

@Test
public void testLambdaQueryWrapper() {
    // select id, username, info, balance from t_user
    // where id = 3 and username like '%o%' and balance >= 1000
    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
            // 设置需要查询的字段
            .select(User::getId, User::getUsername, User::getInfo, User::getBalance)
            // id = 3
            .eq(User::getId, 3)
            // username like '%o%'
            .like(User::getUsername, "o")
            // balance >= 1000
            .ge(User::getBalance, 1000);
    List<User> userList = userMapper.selectList(wrapper);
    userList.forEach(System.out::println);
}

执行该单元测试,可以得到和上面的testQueryWrapper()一样的结果,但这种写法不需要将字段名写死。未来如果需要修改字段名,也不需要这里的逻辑代码。

2.2 自定义SQL

在单元测试testUpdateWrapper(),编写了这样一行代码:.setSql("balance = balance - 200"),这种写法其实也是不好的,因为SQL语句最好都维护在持久层,而不是业务层

为此,MyBatis提供了自定义SQL功能,即利用Wrapper构建复杂的where条件,然后自己定义SQL语句剩余的部分。

也就是说,UPDATE t_user SET balance = balance - 200自己定义,WHERE id in (1, 2, 4)利用Wrapper构建。

2.2.1 基本用法

例如单元测试testUpdateWrapper()可以这样修改:

@Test
public void testUpdateWrapper2() {
    List<Long> ids = Arrays.asList(1L, 2L, 4L);
    // 1.生成SQL
    UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
            // SET balance = balance - 200
            // .setSql("balance = balance - 200")
            // WHERE id in (1, 2, 4)
            .in("id", ids);
    // 2.更新
    // userMapper.update(null, wrapper);
    // 改为调用自定义的Mapper方法,直接传递Wrapper
    userMapper.deductBalanceByIds(200, wrapper);
}

然后在UserMapper中定义deductBalanceByIds()方法:

// com.star.learning.mapper.UserMapper

@Update("UPDATE t_user SET balance = balance - #{money} ${uw.customSqlSegment}")
void deductBalanceByIds(@Param("money") int money, @Param("uw") UpdateWrapper<User> wrapper);

执行修改后的单元测试,执行结果和原来的是一样的。

2.2.2 多表关联

理论上来讲MyBatisPlus是不支持多表查询的,不过仍然可以利用Wrapper构建复杂where条件结合自定义SQL来实现多表查询的效果。

例如,要查询出所有收货地址在北京并且用户id在1、2、4之中的用户,其SQL语句为:

SELECT * FROM t_user u
INNER JOIN t_address a ON a.user_id = u.id
WHERE u.id IN (1,2,4)
AND a.city = '北京'

编写单元测试,利用Wrapper构建复杂where条件,并调用自定义的Mapper方法:

@Test
public void testMultiTableQuery() {
    List<Long> ids = Arrays.asList(1L, 2L, 4L);
    // 1.利用Wrapper构建复杂where条件
    QueryWrapper<User> wrapper = new QueryWrapper<User>()
            .in("u.id", ids)
            .eq("a.city", "北京");
    // 2.调用自定义的Mapper方法
    User user = userMapper.queryUserByIdAndCity(wrapper);
    System.out.println(user);
}
// com.star.learning.mapper.UserMapper

@Select("SELECT * FROM t_user u INNER JOIN t_address a ON a.user_id = u.id ${ew.customSqlSegment}")
User queryUserByIdAndCity(@Param("ew") QueryWrapper<User> wrapper);

执行以上单元测试,结果如下:

==>  Preparing: SELECT * FROM t_user u INNER JOIN t_address a ON a.user_id = u.id WHERE (u.id IN (?,?,?) AND a.city = ?)
==> Parameters: 1(Long), 2(Long), 4(Long), 北京(String)
<==      Total: 1
User(id=2, username=Rose, password=123, phone=13900112223, info={"age": 19, "intro": "青涩少女", "gender": "female"}, status=1, balance=200, createTime=2024-04-21T10:13:35, updateTime=2024-04-21T16:10:20)

2.3 Service接口

MybatisPlus不仅提供了BaseMapper接口,还提供了通用的Service接口及默认实现ServiceImpl,封装了一些常用的service模板方法。

2.3.1 IService

2.3.1.1 save

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

  • save:插入一条记录
  • saveBatch:批量插入多条记录
  • saveOrUpdate:记录存在则更新记录,否则插入一条新记录
  • saveOrUpdateBatch:记录存在则批量修改,否则批量插入
2.3.1.2 remove

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

  • remove:根据条件删除
  • removeById:根据ID删除
  • removeByIds:根据ID批量删除
  • removeByMap:根据Map中的键值对为条件删除
  • removeBatchByIds:批量删除(jdbc批量提交)
2.3.1.3 update

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

  • update(Wrapper<T>):根据UpdateWrapper修改,Wrapper中包含set和where部分
  • update(T,Wrapper<T>):按照T内的数据修改与Wrapper匹配到的数据
  • updateById:根据id修改
  • updateBatchById:根据id批量修改
2.3.1.4 get

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

  • getById:根据id查询
  • getOne(Wrapper<T>):根据Wrapper查询1条记录
  • getBaseMapper:获取对应实体的BaseMapper
  • getMap(Wrapper<T>):根据Wrapper查询1条记录,封装为Map
2.3.1.5 list

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

  • list():查询所有
  • list(Wrapper<T>):根据Wrapper条件查询列表
  • listByIds():根据ID集合查询列表
2.3.1.6 count

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

  • count():查询总记录数
  • count(Wrapper<T>):根据Wrapper条件查询总记录数
2.3.1.7 page

MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口,MyBatisPlus详解,sql,数据库,java,mybatis,mybatisplus,wrapper,后端

  • page(IPage):无条件翻页查询
  • page(IPage, Wrapper<T>):根据Wrapper条件翻页查询

2.3.2 基本用法

创建一个IUserService接口,继承IService接口以拓展方法;同时,自定义UserServiceImpl实现类,继承ServiceImpl实现类,并实现IUserService接口。

// com.star.learning.service.IUserService

public interface IUserService extends IService<User> {
}
// com.star.learning.service.impl.UserServiceImpl

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}

这样配置之后,导入IUserService接口,即可以使用IService接口中定义的各种方法。

接下来,实现下面这个接口:

接口 请求方式 请求路径 请求参数 返回值
新增用户 POST /user/add User

首先,导入相关依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

然后创建一个UserController类,并编写一个addUser()方法:

// com.star.learning.controller.UserController

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserService userService;

    @PostMapping("/add")
    public void addUser(@RequestBody User user) {
        boolean save = userService.save(user);
        System.out.println("新增用户结果 => " + save);
    }
}

最后进行功能测试,调用/user/add接口,查看控制台打印信息:

==>  Preparing: INSERT INTO t_user ( username, password, phone, info, balance ) VALUES ( ?, ?, ?, ?, ? )
==> Parameters: Jim(String), 123456(String), 999(String), {"age": 20, "intro": "佛系青年", "gender": "male"}(String), 500(Integer)
<==    Updates: 1
新增用户结果 => true

接下来再来实现3个接口:

接口 请求方式 请求路径 请求参数 返回值
根据id查询用户 GET /user/{id} id User
根据id集合批量查询用户 GET /user/{id} id List<User>
删除用户 DELETE /user/{id} id

其代码如下:

// com.star.learning.controller.UserController

@GetMapping("/{id}")
public User getById(@PathVariable("id") Long userId) {
    User user = userService.getById(userId);
    System.out.println("根据id查询用户 => " + user);
    return user;
}

@GetMapping
public List<User> queryUserByIds(@RequestParam("ids") List<Long> ids){
    List<User> users = userService.listByIds(ids);
    System.out.println("根据id集合查询用户列表 => " + users);
    return users;
}

@DeleteMapping("/{id}")
public void removeUserById(@PathVariable("id") Long userId){
    boolean remove = userService.removeById(userId);
    System.out.println("根据id删除用户 => " + remove);
}

调用这3个接口,查看控制台打印信息:

// 根据id查询用户
==>  Preparing: SELECT id,username,password,phone,info,status,balance,create_time,update_time FROM t_user WHERE id=?
==> Parameters: 2(Long)
<==      Total: 1
根据id查询用户 => User(id=2, username=Rose, password=123, phone=13900112223, info={"age": 19, "intro": "青涩少女", "gender": "female"}, status=1, balance=200, createTime=2024-04-21T10:13:35, updateTime=2024-04-21T16:10:20)

// 根据id集合批量查询用户
==>  Preparing: SELECT id,username,password,phone,info,status,balance,create_time,update_time FROM t_user WHERE id IN ( ? , ? , ? )
==> Parameters: 1(Long), 2(Long), 3(Long)
<==      Total: 2
根据id集合查询用户列表 => [User(id=2, username=Rose, password=123, phone=13900112223, info={"age": 19, "intro": "青涩少女", "gender": "female"}, status=1, balance=200, createTime=2024-04-21T10:13:35, updateTime=2024-04-21T16:10:20), User(id=3, username=Hope, password=123, phone=13900112222, info={"age": 25, "intro": "上进青年", "gender": "male"}, status=1, balance=20000, createTime=2024-04-21T10:13:35, updateTime=2024-04-21T11:12:48)]

// 根据id删除用户
==>  Preparing: DELETE FROM t_user WHERE id=?
==> Parameters: 2(Long)
<==    Updates: 1
根据id删除用户 => true

可以看到,上述4个接口都直接在Controller类中即可实现,无需编写任何Service代码,非常方便。

不过,一些带有业务逻辑的接口则需要在Service中自定义实现了。例如下面这个接口:

接口 请求方式 请求路径 请求参数 返回值
根据id扣减用户余额 PUT {id}/deduction/{money} id,money
// com.star.learning.controller.UserController

@PutMapping("{id}/deduction/{money}")
public void deductBalance(@PathVariable("id") Long id, @PathVariable("money")Integer money){
    System.out.println("扣减id=" + id + "的用户的余额" + money);
    userService.deductBalance(id, money);
}
// com.star.learning.service.IUserService

public interface IUserService extends IService<User> {
    void deductBalance(Long userId, Integer money);
}
// com.star.learning.service.impl.UserServiceImpl

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public void deductBalance(Long userId, Integer money) {
        // 1.查询用户
        User user = getById(userId);
        System.out.println(user);
        // 2.判断用户状态
        if (user == null || user.getStatus() == 2) {
            throw new RuntimeException("用户状态异常");
        }
        // 3.判断用户余额
        if (user.getBalance() < money) {
            throw new RuntimeException("用户余额不足");
        }
        // 4.扣减余额
        // 2.2节自定义SQL创建了deductBalanceByIds方法可以直接使用
        UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
                .eq("id", userId);
        userMapper.deductBalanceByIds(money, wrapper);
    }
}

调用/user/3/deduction/200接口,查看控制台打印信息:

扣减id=3的用户的余额200
==>  Preparing: SELECT id,username,password,phone,info,status,balance,create_time,update_time FROM t_user WHERE id=?
==> Parameters: 3(Long)
<==      Total: 1
User(id=3, username=Hope, password=123, phone=13900112222, info={"age": 25, "intro": "上进青年", "gender": "male"}, status=1, balance=20000, createTime=2024-04-21T10:13:35, updateTime=2024-04-21T11:12:48)
==>  Preparing: UPDATE t_user SET balance = balance - ? WHERE (id = ?)
==> Parameters: 200(Integer), 3(Long)
<==    Updates: 1

本节完,更多内容请查阅分类专栏:MyBatisPlus详解

本文涉及代码下载地址:https://gitee.com/weidag/mybatis_plus_learning.git

感兴趣的读者还可以查阅我的另外几个专栏:文章来源地址https://www.toymoban.com/news/detail-857943.html

  • SpringBoot源码解读与原理分析(已完结)
  • MyBatis3源码深度解析(已完结)
  • Redis从入门到精通(已完结)
  • 再探Java为面试赋能(持续更新中…)

到了这里,关于MyBatisPlus详解(二)条件构造器Wrapper、自定义SQL、Service接口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • MyBatis-Plus——条件构造器Wapper、QUeryWrapper、UpdateWrapper、LambdaQueryWrapper、LambdaUpdateWrapper(详解)

    目录 一、条件构造器简介 二、QueryWrapper组装查询条件 三、QueryWrapper组装排序条件 四、QueryWrapper组装删除条件 五、QueryWrapper实现修改功能 六、QueryWrapper条件的优先级 七、QueryWrapper组装select字句(查询指定字段) 八、QueryWrapper组装子查询 九、UpdateWrapper实现修改功能 十、Q

    2024年02月07日
    浏览(38)
  • Java中使用es条件构造器BoolQueryBuilder

    由于es在java中查询没法像mybatis那样方便,而且es的构造器使用也比较繁琐,理解不是很方便,所以写一篇文章来记录es构造器BoolQueryBuilder查询时各种条件的构造的正确姿势。 1.构造准备 2.条件构造 must可用filter代替,查询效率会更高,因为must会对结果进行_score评估 3.构造完成

    2024年02月11日
    浏览(43)
  • MyBatis-Plus深入 —— 条件构造器与插件管理

            在前面的文章中,荔枝梳理了一个MyBatis-Plus的基本使用、配置和通用Service接口,我们发现在MyBatis-Plus的辅助增强下我们不再需要通过配置xml文件中的sql语句来实现基本的sql操作了,不愧是最佳搭档!在这篇文章中,荔枝会着重梳理有关MyBatis-Plus的两个知识点:条

    2024年02月09日
    浏览(37)
  • MyBatis-Plus使用条件构造器实现不同条件的查询,更新删除操作

    Wrapper 是所有条件构造器的父类,作用是生成条件语句,即where后面的sql子句 在调用查询,更新,删除操作时,需要根据条件进行判断,可以使用条件构造器进行组合条件,生成where后面条件子句 QueryWrapper,UpdateWrapper LambdaQueryWrapper,LambdaUpdateWrapper UpdateWrapper提供了set方法,可以

    2024年02月15日
    浏览(32)
  • Mybatis-Plus(三)--Mybatis-Plus配置和条件构造器

    在MP中有大量的配置,其中有一部分是Mybatis原生的配置,另一部分是MP的配置,详情:https://mybatis.plus/config 【1】configLocation--自己单独的MyBatis配置的路径 SpringMVC的xml中写法: 【2】mapperLocations--MyBatis Mapper所对应的XML文件位置 如果你在Mapper中有自定义方法(XML中有自定义实现

    2024年02月15日
    浏览(50)
  • Java中构造器详解(类的五成员之三:构造器)

    先看文章目录,大致了解知识点结构,直接点击文章目录可以跳转到文章指定位置。 Java的基本单位是类,类中包含五个部分,这篇写的是 构造器 。 (1)变量 (2)方法 (3)构造器 (4)初始化块 (5)内部类 ①构造器是处于Java类中的一个方法,最大的作用创建对象时执行

    2024年02月08日
    浏览(36)
  • MyBatis-Plus条件构造器[常用的模糊查询、排序查询、逻辑查询和指定字段查询案例]

    Mybatis-Plus知识点[MyBatis+MyBatis-Plus的基础运用]_心态还需努力呀的博客-CSDN博客  Mybatis-Plus+SpringBoot结合运用_心态还需努力呀的博客-CSDN博客 MyBaits-Plus中@TableField和@TableId用法_心态还需努力呀的博客-CSDN博客 MyBatis-Plus中的更新操作(通过id更新和条件更新)_心态还需努力呀的博客

    2024年02月06日
    浏览(78)
  • 7.5 构造器详解

    7.5 构造器详解 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点: 必须和类的名字相同 必须没有返回类型,也不能写void 一个类即使什么都不写都会存在一个构造方法。 构造器的作用 可以实例化一些初始值,比如一些游戏

    2024年02月14日
    浏览(29)
  • Scala第六章节(类和对象的定义、访问修饰符和构造器的用法、main方法的实现形式、伴生对象的使用以及工具类的案例)

    章节目标 掌握类和对象的定义 掌握访问修饰符和构造器的用法 掌握main方法的实现形式 掌握伴生对象的使用 掌握定义工具类的案例 1. 类和对象 Scala是一种函数式的面向对象语言, 它也是支持面向对象编程思想的,也有类和对象的概念。我们依然可以基于Scala语言来开发面向

    2024年03月19日
    浏览(36)
  • Java 构造器

    2024年02月12日
    浏览(100)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包