百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Mybatis-Plus,真香(mybatis-plus简介)

bigegpt 2024-08-03 11:47 8 浏览

前言

mybatis相信都不陌生,目前互联网公司大部分都使用mybatis作为持久层框架,无他,因为可以直接在xml文件中编写SQL语句操作数据库,灵活。但是我们在使用的时候,也会发现有很多增删改查的SQL是每个表都会有的基本操作,如果每个表都写一套增删改查的SQL显然是非常耗时耗力的。

于是乎,就有了mybatis-plus这个框架。正如官网所说,mybatis-plus是为简化开发而生

mybatis-plus有以下特点:

  • 只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
  • 只需简单配置,即可快速进行单表CRUD操作,节省大量时间。
  • 代码生成,物理分页,性能分析等功能一应俱全。

一、整合mybatis-plus

这里用的是SpringBoot2.5.2做演示。首先导入依赖:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- 引入 mybatis-plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.0</version>
</dependency>

然后在application.properties文件配置数据库信息:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/user?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=root123456
#mapper.xml文件路径地址
mybatis-plus.mapper-locations=classpath:mapper/*Mapper.xml

在启动类加上扫描注解:

@SpringBootApplication
@MapperScan(basePackages = "com.yehongzhi.mydemo.mapper")
public class MydemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(MydemoApplication.class, args);
    }
}

其实这样就完成了,但是我们要建个表进行测试。

CREATE TABLE `user` (
  `id` char(36) NOT NULL DEFAULT '' COMMENT 'ID',
  `name` varchar(255) DEFAULT '' COMMENT '姓名',
  `age` int(3) DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 初始化4条数据
INSERT INTO `user`.`user` (`id`, `name`, `age`) VALUES ('1345fc0985b111eba0e488d7f66fdab8', '观辰', '20');
INSERT INTO `user`.`user` (`id`, `name`, `age`) VALUES ('d47561e885b011eba0e488d7f66fdab8', '姚大秋', '30');
INSERT INTO `user`.`user` (`id`, `name`, `age`) VALUES ('ef2741fe87f011eba0e488d7f66fdab8', '周星驰', '60');
INSERT INTO `user`.`user` (`id`, `name`, `age`) VALUES ('ff784f6b85b011eba0e488d7f66fdab8', '李嘉晟', '33');

建了表之后,再创建一个User实体类对应:

//表名
@TableName("user")
public class User {
 //主键
    @TableId(type = IdType.UUID)
    private String id;
 //姓名
    private String name;
 //年龄
    private Integer age;
    //getter、setter方法
}

接着创建UserMapper接口类,,然后继承BaseMapper:

@Repository
public interface UserMapper extends BaseMapper<User> {
    
}

创建一个UserMapper.xml与UserMapper对应:

<?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.yehongzhi.mydemo.mapper.UserMapper">

</mapper>

最后我们写一个UserService接口,查询user表:

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;

    @Override
    public List<User> getList() {
        return userMapper.selectList(null);
    }
}

启动项目,测试是没问题的:

二、CRUD操作

整合完了之后,按照mybatis-plus的官方说明,是有简单的单表CRUD操作功能。

这些单表的CRUD操作其实都放在BaseMapper里面了,所以当我们继承了BaseMapper类之后,就会获得mybatis-plus的增强特性,其中就包括单表的CRUD操作。

1、insert操作

BaseMapper直接提供一个insert()方法,传一个实体类。

@Service
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;
    
    @Override
    public int insertOne(User user) {
        return userMapper.insert(user);
    }
}

接着在Controller调用,因为在User类上面贴了注解@TableId,所以会自动生成ID。

@TableName("user")
public class User {
    @TableId(type = IdType.UUID)
    private String id;
    //省略...
}

Controller层代码:

@RequestMapping("/insert")
public String insertUser(@RequestParam(name = "name") String name,
                         @RequestParam(name = "age") Integer age) {
    User user = new User();
    user.setName(name);
    user.setAge(age);
    //在实体类使用了@TableId注解,ID会自动生成
    int i = userService.insertOne(user);
    return i == 1 ? "success" : "fail";
}

2、update操作

BaseMapper直接提供一个updateById()方法,传一个实体类。

@Override
public int updateOne(User user) {
    return userMapper.updateById(user);
}

Controller层代码:

@RequestMapping("/update")
public String updateUser(@RequestParam(name = "id") String id,
                         @RequestParam(name = "name",required = false) String name,
                         @RequestParam(name = "age",required = false) Integer age) {
    User user = new User();
    user.setId(id);
    user.setName(name);
    user.setAge(age);
    int i = userService.updateOne(user);
    return i == 1 ? "success" : "fail";
}

3、delete操作

BaseMapper直接提供一个deleteById()方法,传主键值。

@Override
public int deleteOne(String id) {
    return userMapper.deleteById(id);
}

Controller层代码:

@RequestMapping("/delete")
public String deleteUser(@RequestParam(name = "id") String id) {
    int i = userService.deleteOne(id);
    return i == 1 ? "success" : "fail";
}

除此之外,还有批量删除deleteBatchIds方法,传主键值的集合:

@Override
public int deleteBatch(List<String> ids){
    return userMapper.deleteBatchIds(ids);
}

Controller层代码:

@RequestMapping("/deleteBatch")
public String deleteBatchUser(@RequestParam(name = "ids") String ids) {
    List<String> list = Arrays.asList(ids.split(","));
    int i = userService.deleteBatch(list);
    return i == list.size() ? "success" : "fail";
}

三、条件构造器(Wrapper)

条件构造器在Mybatis-plus各种方法中都有出现,比如:

Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

Wrapper通俗点理解就是定义where语句后面的查询条件,是Mybatis-Plus里功能比较强大的工具。Wrapper是一个抽象类,下面有很多子类,我们先看个类图混个眼熟。

常用的子类实现有四个,分别是:

  • QueryWrapper
  • UpdateWrapper
  • LambdaQueryWrapper
  • LambdaUpdateWrapper

QueryWrapper

主要用于生成where条件,举个例子,我们用name查询user表:

public List<User> queryUserByName(String name) {
    //相当于:SELECT * FROM user WHERE name = ?
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //eq()表示相等
    queryWrapper.eq("name", name);
    return userMapper.selectList(queryWrapper);
}

我们看日志打印:

==>  Preparing: SELECT id,name,age FROM user WHERE name = ?
==> Parameters: 姚大秋(String)
<==    Columns: id, name, age
<==        Row: d47561e885b011eba0e488d7f66fdab8, 姚大秋, 30
<==      Total: 1

假如我们要like查询,可以这样写:

public List<User> queryUserLikeName(String name) {
    //相当于:SELECT * FROM user WHERE name like %#{name}%
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("name",name);
    return userMapper.selectList(queryWrapper);
}

假如要查询年龄大于30岁,可以这样:

public List<User> queryUserGtByAge(int age) {
    //相当于:SELECT * FROM user WHERE age > ?
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.gt("age", age);
    //小于是lt()
    //大于等于是ge()
    //小于等于是le()
    //范围的话,则使用between()
    return userMapper.selectList(queryWrapper);
}

如果要查询某个字段不为空,可以这样:

public List<User> queryUserByNameNotNull() {
    //相当于:SELECT * FROM user WHERE name IS NOT NULL
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.isNotNull("name");
    //查询某个字段为空,则使用isNull()
    return userMapper.selectList(queryWrapper);
}

如果使用IN查询,可以这样:

public List<User> queryUserByIds(List<String> ids) {
    //相当于:SELECT * FROM user WHERE name IN ('id1','id2');
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.in("id", ids);
    //相反也提供了notIn()方法
    return userMapper.selectList(queryWrapper);
}

如果需要排序,可以这样写:

public List<User> queryUserOrderByAge() {
    //相当于:SELECT * FROM user ORDER BY age ASC
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.orderByAsc("age");
    //相反的,如果降序则使用orderByDesc()方法
    return userMapper.selectList(queryWrapper);
}

如果需要子查询,可以这样写:

public List<User> queryUserInSql() {
    //相当于:SELECT * FROM user WHERE id IN (SELECT id FROM user WHERE age > 30)
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.inSql("id","select id from user where age > 30");
    return userMapper.selectList(queryWrapper);
}

大部分的方法都是源自AbstractWrapper抽象类,除此之外还有很多功能,这里就不一一介绍下去了,有兴趣的可以到官网的条件构造器慢慢探索。

UpdateWrapper

UpdateWrapper也是AbstractWrapper抽象类的子类实现,所以上述的设置条件的方法都有,不同的是,UpdateWrapper会有set()和setSql()设置更新的值。举个例子:

public int updateUserNameById(String id, String name) {
    //相当于:UPDATE user SET name = ? where id = ?
    UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
    userUpdateWrapper.eq("id", id);
    //设置set关键字后面的语句,相当于set name = #{name}
    userUpdateWrapper.set("name", name);
    return userMapper.update(new User(), userUpdateWrapper);
}

setSql()就是设置SET关键字后面拼接的部分SQL语句,举个例子:

public int updateUserBySql(String id, String name) {
    //相当于:UPDATE user SET name = ? where id = ?
    UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
    userUpdateWrapper.setSql("name = '" + name + "'");
    userUpdateWrapper.eq("id", id);
    return userMapper.update(new User(), userUpdateWrapper);
}

setSql()就是纯粹的SQL语句拼接,我们可以看到SET后面接的是name='大D',而不是占位符会有SQL注入的风险。

==>  Preparing: UPDATE user SET name = '大D' WHERE id = ?
==> Parameters: d47561e885b011eba0e488d7f66fdab8(String)
<==    Updates: 1

LambdaQueryWrapper

用LambdaQueryWrapper的好处在于消除硬编码,比如QueryWrapper在查询name=?时,需要这样写:

QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//使用"name"字符串,就是硬编码
queryWrapper.eq("name", name);

如果换成LambdaQueryWrapper就可以这样写:

public List<User> lambdaQueryUserByName(String name) {
    //相当于:SELECT id,name,age FROM user WHERE name = ?
    LambdaQueryWrapper<User> lambdaQueryWrapper = new QueryWrapper<User>().lambda();
    lambdaQueryWrapper.eq(User::getName, name);
    return userMapper.selectList(lambdaQueryWrapper);
}

再比如使用模糊查询,可以这样写:

public List<User> lambdaQueryUserLikeName(String name) {
    LambdaQueryWrapper<User> lambdaQueryWrapper = new QueryWrapper<User>().lambda();
    lambdaQueryWrapper.like(User::getName, name);
    return userMapper.selectList(lambdaQueryWrapper);
}

LambdaUpdateWrapper

跟上面差不多,LambdaUpdateWrapper也可以消除硬编码:

public int lambdaUpdateUserNameById(String id, String name) {
    //相当于:UPDATE user SET name=? WHERE id = ?
    LambdaUpdateWrapper<User> lambdaUpdateWrapper = new UpdateWrapper<User>().lambda();
    lambdaUpdateWrapper.set(User::getName, name);
    lambdaUpdateWrapper.eq(User::getId, id);
    return userMapper.update(new User(), lambdaUpdateWrapper);
}

分页查询

Mybatis-plus提供了分页插件支持分页查询,只需要几个步骤即可实现。

首先添加一个配置类:

@Configuration
public class MybatisPlusConfig {
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

第二步,在UserMapper类里定义分页查询方法:

@Repository
public interface UserMapper extends BaseMapper<User> {
 //分页查询方法
    IPage<User> selectPageByName(Page<User> page, @Param("name") String name);
}

对应的UserMapper.xml方法:

<select id="selectPageByName" parameterType="java.lang.String" resultType="com.yehongzhi.mydemo.model.User">
    select * from `user` where name = #{name}
</select>

第三步,在userService里调用:

public IPage<User> selectPageByName(long pageNo, long pageSize, String name) {
    Page<User> page = new Page<>();
    //设置当前页码
    page.setCurrent(pageNo);
    //设置每页显示数
    page.setSize(pageSize);
    return userMapper.selectPageByName(page, name);
}

最后写个Controller接口测试:

@RequestMapping("/queryPage/ByName")
public IPage<User> selectPageByName(@RequestParam("pageNo") long pageNo,
                                    @RequestParam("pageSize") long pageSize,
                                    @RequestParam("name") String name) {
    return userService.selectPageByName(pageNo, pageSize, name);
}

查看控制台日志:

==>  Preparing: SELECT COUNT(1) FROM `user` WHERE name = ?
==> Parameters: 杜琪峰(String)
<==    Columns: COUNT(1)
<==        Row: 1
==>  Preparing: select * from `user` where name = ? LIMIT ?,?
==> Parameters: 杜琪峰(String), 0(Long), 10(Long)
<==    Columns: id, name, age
<==        Row: d47561e885b011eba0e488d7f66fdab8, 杜琪峰, 30
<==      Total: 1

分页查询成功!

自定义主键生成器

有时在实际开发中,可能会遇到,Mybatis-plus提供的主键生成策略并不能满足,需要自定义主键ID生成策略,怎么设置呢?

很简单,根据官网的说明,我们先定义一个主键生成器:

@Component
public class SnowflakeKeyGenerator implements IdentifierGenerator {
 //自己实现的一个雪花ID生成工具类
    @Resource
    private SnowflakeIdWorker snowflakeIdWorker;

    @Override
    public Number nextId(Object entity) {
        //使用雪花ID生成器,生成一个雪花ID
        long nextId = snowflakeIdWorker.nextId();
        System.out.println(String.format("使用自定义ID生成器,生成雪花ID:%s", nextId));
        return nextId;
    }
}

然后我们在需要使用该自定义ID生成器的实体类上面加上注解属性:

@TableName("user")
public class User {
 //属性设置为:IdType.ASSIGN_ID
    @TableId(type = IdType.ASSIGN_ID)
    private String id;
 
    //省略...
}

接着测试一下,我们可以看到控制台有打印日志:

总结

除了上面介绍的功能之外,Mybatis-plus还有很多功能,比如:代码生成器、扩展等等。这里就不再一一介绍了,实际上我们掌握上面介绍的CRUD、条件构造器、分页查询、自定义主键策略,基本上已经足够日常的开发。

当然如果你觉得会用还不够,还想要看懂框架的源码实现,那没问题。下一篇文章,我就讲讲框架的源码分析,敬请期待,

非常感谢你的阅读,希望这篇文章能给到你帮助和启发。

觉得有用就点个赞吧,你的点赞是我创作的最大动力~

我是一个努力让大家记住的程序员。我们下期再见!!!

能力有限,如果有什么错误或者不当之处,请大家批评指正,一起学习交流!

相关推荐

当Frida来“敲”门(frida是什么)

0x1渗透测试瓶颈目前,碰到越来越多的大客户都会将核心资产业务集中在统一的APP上,或者对自己比较重要的APP,如自己的主业务,办公APP进行加壳,流量加密,投入了很多精力在移动端的防护上。而现在挖...

服务端性能测试实战3-性能测试脚本开发

前言在前面的两篇文章中,我们分别介绍了性能测试的理论知识以及性能测试计划制定,本篇文章将重点介绍性能测试脚本开发。脚本开发将分为两个阶段:阶段一:了解各个接口的入参、出参,使用Python代码模拟前端...

Springboot整合Apache Ftpserver拓展功能及业务讲解(三)

今日分享每天分享技术实战干货,技术在于积累和收藏,希望可以帮助到您,同时也希望获得您的支持和关注。架构开源地址:https://gitee.com/msxyspringboot整合Ftpserver参...

Linux和Windows下:Python Crypto模块安装方式区别

一、Linux环境下:fromCrypto.SignatureimportPKCS1_v1_5如果导包报错:ImportError:Nomodulenamed'Crypt...

Python 3 加密简介(python des加密解密)

Python3的标准库中是没多少用来解决加密的,不过却有用于处理哈希的库。在这里我们会对其进行一个简单的介绍,但重点会放在两个第三方的软件包:PyCrypto和cryptography上,我...

怎样从零开始编译一个魔兽世界开源服务端Windows

第二章:编译和安装我是艾西,上期我们讲述到编译一个魔兽世界开源服务端环境准备,那么今天跟大家聊聊怎么编译和安装我们直接进入正题(上一章没有看到的小伙伴可以点我主页查看)编译服务端:在D盘新建一个文件夹...

附1-Conda部署安装及基本使用(conda安装教程)

Windows环境安装安装介质下载下载地址:https://www.anaconda.com/products/individual安装Anaconda安装时,选择自定义安装,选择自定义安装路径:配置...

如何配置全世界最小的 MySQL 服务器

配置全世界最小的MySQL服务器——如何在一块IntelEdison为控制板上安装一个MySQL服务器。介绍在我最近的一篇博文中,物联网,消息以及MySQL,我展示了如果Partic...

如何使用Github Action来自动化编译PolarDB-PG数据库

随着PolarDB在国产数据库领域荣膺桂冠并持续获得广泛认可,越来越多的学生和技术爱好者开始关注并涉足这款由阿里巴巴集团倾力打造且性能卓越的关系型云原生数据库。有很多同学想要上手尝试,却卡在了编译数据...

面向NDK开发者的Android 7.0变更(ndk android.mk)

订阅Google官方微信公众号:谷歌开发者。与谷歌一起创造未来!受Android平台其他改进的影响,为了方便加载本机代码,AndroidM和N中的动态链接器对编写整洁且跨平台兼容的本机...

信创改造--人大金仓(Kingbase)数据库安装、备份恢复的问题纪要

问题一:在安装KingbaseES时,安装用户对于安装路径需有“读”、“写”、“执行”的权限。在Linux系统中,需要以非root用户执行安装程序,且该用户要有标准的home目录,您可...

OpenSSH 安全漏洞,修补操作一手掌握

1.漏洞概述近日,国家信息安全漏洞库(CNNVD)收到关于OpenSSH安全漏洞(CNNVD-202407-017、CVE-2024-6387)情况的报送。攻击者可以利用该漏洞在无需认证的情况下,通...

Linux:lsof命令详解(linux lsof命令详解)

介绍欢迎来到这篇博客。在这篇博客中,我们将学习Unix/Linux系统上的lsof命令行工具。命令行工具是您使用CLI(命令行界面)而不是GUI(图形用户界面)运行的程序或工具。lsoflsof代表&...

幻隐说固态第一期:固态硬盘接口类别

前排声明所有信息来源于网络收集,如有错误请评论区指出更正。废话不多说,目前固态硬盘接口按速度由慢到快分有这几类:SATA、mSATA、SATAExpress、PCI-E、m.2、u.2。下面我们来...

新品轰炸 影驰SSD多款产品登Computex

分享泡泡网SSD固态硬盘频道6月6日台北电脑展作为全球第二、亚洲最大的3C/IT产业链专业展,吸引了众多IT厂商和全球各地媒体的热烈关注,全球存储新势力—影驰,也积极参与其中,为广大玩家朋友带来了...