Mybatis-plus
本文最后更新于116 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
今天先试试水,先创建一个大概能看的笔记
好,出于事态紧急,我们直接空降mybatis-plus吧

然后就是这里跟的是https://cyborg2077.github.io/2022/09/20/MyBatisPlus/
这篇笔记做的

额,就是不对底层逻辑进行过多死磕,大概了解一下用法,咱不做理论大师,但咱得向这些大师看齐,多多学习

他这边的技术栈大概就是 SpringBoot+Mybatis+MySQL

步骤一
首先是建表
首先之前我只用过SQLserver,但似乎MySQL的语法类似,所以我就写类似的吧,顺便帮我回忆一点基本语法吧,等这篇笔记写完我让Chat帮我查查错误

//
create table user(
     id bigint(20) primary key auto_increment,
     name varchar(32)  not null,
     password varchar(32) not null,
     age int(3) not null,
     tel varchar(32) not null
);

insert into user values(1,'用户1','666','12','1234567);
insert into user values(2,'用户2','995995','21','120');
insert into user values(3,'用户3','4869','82','119')

步骤二

然后就是配依赖,用的是mybatis-plus 3.4.1的版本,然后看到他这边用的好像是druid这个连接池,我们还是默认用Hikari作为连接池吧,不用特地配置他的以来了

<!-- Web 项目 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- JDBC 基础(可选,很多时候 web starter 里已经带了) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!-- MyBatis-Plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot3-starter</artifactId>
    <version>3.5.14</version>
</dependency>

<!-- MySQL 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- Lombok(可选,简化实体类) -->
  <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
</dependency>

然后就是这边application我们把后缀从properties改成yaml,这样更规范

大概就是这么个结构

spring:
   datasource:
     driver-class-name:com.mysql.cj.jdbc.Driver
     url:/*那就是自己的数据库链接了*/
     username:
     password:

mybatis-plus:
    configuration;
      log-impl:org.apache.ibatis.logging.stdout.StdOutImpl

然后这些造完就把对应数据库的entity建好就行了,我记得
lombok是可以帮我创建好他基本的set和get方法

然后就是mapper

@Mapper
public inetrface UserMapper extends BaseMapper<User>{
}

就差不多这样,其实很方便的都帮我们创建完了,我比较喜欢叫这玩意叫mapper而非dao,因为dao有种提刀砍人的谐音感观感不好,这就类似spring里面的bean给我带来很差的观感一样,但我还找不到替换词

然后就是这个extends的这个basemapper<User>这个玩意,其实也类似预制菜一样的东西,帮我们直接把他的

insert(T entity)
deleteById(Serializable id)
updateById(T entity)
T selectById(Serializable id)
List<T>selectList(Wrapper<T>queryWrapper)

这些基础功能给创建完了,其实就直接用就行了,如果还有其他功能实现的需求就需要去自己写了

然后这里这个注解,也就是这个@Mapper,是告诉你mybatis说“这接口是一个mapper,对其生成类并注册bean”
和sql关系最近的就是这个接口了,就类似仓库和仓库管理员的关系了

然后你就建议的搭一个controller去测试一下,也是需要用到一个注解好像叫@RestController,可以让我们到postman里面去测试我们写的方法,比如我们需要获取我们数据库里面用户的信息就可以用@GetMapping这个注解,这里就不多说了,目前在读的文章的作者应该会在后面讲到,我就不瞎说了


步骤三

额,这边讲了MP(也就是mybatis-plus)的基本性质
那这边直接贴作者的写的吧(因为我大概也不会一个字一个字敲了,懒是这样的)

MP的特性:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 – Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

然后就是挺神奇的就是mapper会在和模型名同名的表里面查找,就比如我写BaseMapper<User>,他就自己跑去找我数据库里面和User同名的表
那如果你就是不想写同名,那你也可以用@TableName注解,比如数据表叫tb_user但数据类叫User,那就再User类上加上注解,也就是@TableName(“tb_user”)

接下来就是这个Lombok,这个玩意也挺方便的说,这个是一个java类库,版本由SpringBoot管理版本号的

基本注解如下

  • @Setter:为模型类的属性提供setter方法
    • @Getter:为模型类的属性提供getter方法
    • @ToString:为模型类的属性提供toString方法
    • @EqualsAndHashCode:为模型类的属性提供equals和hashcode方法
    • @Data:是个组合注解,包含上面的注解的功能
    • @NoArgsConstructor:提供一个无参构造函数
    • @AllArgsConstructor:提供一个包含所有参数的构造函数

我靠,好像我这样写不光别人看不懂,我自己也P都看不懂,我明天高低得列个表格来列出每个东西的注释或者方法(包括重载和实际用法),今天先睡了,我看看现在几点,2025.11.27 0:53 看到3.3.3,当然我还没写笔记写到这里来

OK现在是2025 11.27 22.23,比较晚了明天还有早八就随便写点吧


然后就是这个查询,当初我刚用的时候就有很多疑问,
那总之我这里先列出来吧

步骤四

MyBatis-Plus 几种常见查询方式对比

查询方式写法示例是否写字符串列名主要用途 / 场景优点缺点 / 注意点
直接查全部(无条件)userMapper.selectList(null);快速查询整张表所有数据写法最简单,看库里现在到底有什么数据只能查全部,不能加 where 条件
QueryWrapperjava\nQueryWrapper<User> qw = new QueryWrapper<>();\nqw.eq(\"age\", 18);\nqw.like(\"name\", \"张\");\nuserMapper.selectList(qw);\n✅ 要早期/简单 demo,条件不多时API 简单直白,和 SQL 很像列名是字符串:拼错编译器不报错,重构易踩坑
LambdaQueryWrapperjava\nLambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();\nlqw.eq(User::getAge, 18)\n .like(User::getName, \"张\");\nuserMapper.selectList(lqw);\n❌ 不要日常开发推荐用;需要保证重构安全、IDE 友好User::getXxx 写列名,编译期能检查,字段改名不易炸写法比字符串略长一点,但基本没啥副作用
带条件参数的 LambdaQueryWrapperjava\nLambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();\nlqw.eq(age != null, User::getAge, age)\n .like(StringUtils.hasText(name), User::getName, name);\nuserMapper.selectList(lqw);\n❌ 不要可选条件查询:有值才拼条件,没有就略过boolean condition 控制是否拼接某个 where 条件初看有点绕,但一旦写过一次就离不开
lambdaQuery() 链式查询(Service)java\nList<User> list = userService.lambdaQuery()\n .eq(User::getAge, 18)\n .like(User::getName, \"张\")\n .list();\n❌ 不要使用 MP 自带的 ServiceImpl 时,写查询更顺手语法更链式,看起来像“从 Service 直接开口要数据”依赖 ServiceImpl,不是所有项目都用这套 Service 结构

怎么说呢,就是讲一下这个LambdaQueryWrapper和这个QueryWrapper的区别吧,在进行查询的时候QueryWrapper是根据字符串进行查询的,但这就会导致说你要是把字符输错了他也不会报错,但是LambdaQueryWrapper是引用方法的,所以你要是输入的方法错了他就会报错,来个简单的例子

比如QueryWrapper

QueryWrapper <User>qw=new QueryWrapper<>();
qw.lt("age",18);//这里是直接输入age这个字符的

然后就是LambdQueryWrapper

LambdaQueryWrapper <User>lqw= new LambdaQueryWrapper<>();
lqw.lt(User::getAge(),18);//而这里是引用方法的

所以为了开发方便一般都会用lambdaQueryWrapper

然后就是我经常混淆的一点就是我以为这些Wrapper是先查询我们数据库,然后再通过条件筛选将我们需要的那几行结果存储到它本身,但其实并不是,他其实就是个类似说明书的作用,真正链接并查询的是类似selectList()这种方法
就类似

List<User> result=userMapper.selectList(lqw);//这里面的参数就是lqw,也就是他会告诉这个selectList这个方法说,我需要你按照lqw里面的条件去我数据库对应的表里找符合条件的数据,这样其实就省去了我们很多麻烦,因为按照正常的spring写法,我们得额外写那个xml创建方法进行查询,但现在我们只需要利用MP封装完得方法直接使用就行了,当然这些只是基础需求可以让我们偷懒的,如果有其他业务需求当然还是得我们自己手搓xml

好了明天有早八就先到这里了吧,今天就是写了一点昨天晚上没写完的笔记内容,但是读文章的进度还没推进,现在是2025 11.27 23:33


步骤五

好的今天是12.1然后现在是23:21,对已经过去好几天了我才更新(懒鬼是这样的)

然后就是这几个比较有意思的注解啊,就是类似我们之前讲过的那个TableName,我直接在这边列个表吧看的比较清楚一点(这个编辑模式下看这个表格是真的乱)

注解名类型(所在包)作用位置主要作用说明
@TableNamecom.baomidou.mybatisplus.annotation.TableName类上指定实体类对应的数据库表名、schema、resultMap 等
@TableIdcom.baomidou.mybatisplus.annotation.TableId字段上指定主键字段名,配置主键生成策略(IdType)
@TableFieldcom.baomidou.mybatisplus.annotation.TableField字段上(非主键)指定普通字段名及各种字段策略、自动填充等

怎么说呢,就是,咱先按这个顺序来讲吧,首先就是这个TableName,一般咱用到的也就是那个value这个属性,他指的是你这个已经链接的数据库的指定表名(如果你怕连错的话就可以添加一个这个)

@TableName("tb_user)
@Data
public class User{

}//类似于这样

然后就是这个TableId,一般常用的属性就是value还有这个type,value这玩意默认就是设置数据库表主键名称的比如

@TableName("tb_user")  
@Data  
public class User {  
    @TableId(type = IdType.AUTO)  
    private Long id;  
    private String name;  
    private String password;  
    private Integer age;  
    private String tel;  
    @TableField(exist = false)  
    private Integer online;  
}

这样咱的id就被设置为主键了,然后就是这个什么,这个type,他是可以设置我们这个主键规则的

枚举值含义说明
AUTO数据库自增
NONE未指定(跟随全局配置,一般是 INPUT)
INPUT插入前手动 set 主键
ASSIGN_IDMP 分配长整型/字符串雪花 ID
ASSIGN_UUIDMP 分配 32 位 UUID 字符串

就差不多是这样的,Auto是默认的的自增(即按照你表的规则自增,比如一次增加3或者5之类的)

然后这个none和input基本算是同流合污,input就是让你自己输入主键的值,none的默认好像也是Input
接下来就是这个ASSIGN_ID和这个ASSIGN_UUID

这俩个是跟分布式有关系的,一旦你数据量太大,一台服务器装不下就需要多台数据库服务器,那么一个数据类的内容可能会被存在不同的数据库服务器上吗,这时候就需要这俩了
①首先是这个ASSIGN_ID,他是通过一个叫雪花算法的东西生成的ID,数据类型为Long,一般都是由64位构成的整数

首位用来表示正负(也就是我们计算机组成原理里面那玩意)

随着他后面的41位表示时间戳,毫秒级别的记录时间

在接下来的10位用来记录工作机器的ID,高五位用来记录数据中心ID,低五位用来记录工作节点ID

最后的序列号ID占12位从0毫秒开始叠加最多到4095,共产生4096个ID
//其实我很想把图放在这里面来详细解释可惜笔记没办法放图好像

②然后就是这个UUID了
数据类型为varchar,长度需要大于32位,对就这样,好像也没什么更多好说的了

哦对了然后就是我们可以在application.yaml里面配置MP的数据库配置,比如我多个表都需要将数据类型设置为assgin_id,那可以这么配置

mybatis-plus:  
  global-config:  
    db-config:  
      id-type: assign_id

还有就是如果你的数据库名有固定的前缀也可以加上一个
tablke_prefix:tb_//形如tb_这种的
这样你就不用每次重复写这玩意了

OK了现在是12.2 0:05了,其实这就是在对我白天上课摸鱼时看的笔记的补充,所以现在思路还算是挺清晰的,我打算微服务和redis学完后自己部署一个网站,明天把MP这章完结了就开始推下一章吧,到时候看能不能把笔记的格式再美化一下

好的现在是 12.4 20:12,偷懒了一天,打算把MP这章完结一下子

其实就是多记录操作

@Test  
void testDeleteByIds(){  
    ArrayList<Long> list = new ArrayList<>();  
    list.add(1572543345085964289L);  
    list.add(1572554951983460354L);  
    list.add(1572555035978534913L);  
    userDao.deleteBatchIds(list);  
}

形如上述这种写法,就是将list这个数组作为参数传入userMapper里面的这个方法(似乎也是BaseMapper里面提供的方法),当然有delete也会有select,用法也差不多,也就是selectBatchIds(list)

还有就是MP里面也可以执行对数据库的操作,比如

//表名前缀和id生成策略在yml配置文件写了  
@Data  
public class User {  
    private Long id;  
    private String name;  
    private String password;  
    private Integer age;  
    private String tel;  
    //新增delete属性  
    //value为正常数据的值(在职),delval为删除数据的值(离职)  
    @TableLogic(value = "0",delval = "1")  
    private Integer deleted;  
}

这样,我们就添加了一个属性,叫deleted
这样我们执行userMapper.deleteById(1)时,就会在数据库里执行

UPDTAE user set deleted=1 where userId=1

也就是他不会真的把你数据库里的数据删掉,只是打个标记罢了,这样就不会在实际业务里面出现无主信息

那么,当你执行

userMapper.selectList(null)

时,数据库就会执行

select*from user where deleted=0;

一般这种在业务中就是类似“冻结/禁用/停职”这种,我们不真的把数据删掉而是做标记保留

那如果我们要全局应用的话,就可以在配置文件里面直接做类似添加

mybatis-plus:  
    global-config:  
    db-config:  
        ## 逻辑删除字段名  
        logic-delete-field: deleted  
        ## 逻辑删除字面值:未删除为0  
        logic-not-delete-value: 0  
        ## 逻辑删除字面值:删除为1  
        logic-delete-value: 1

那么就对TableLogic做个总结吧

名称TableLogic
类型属性注解
位置模型类中用于表示删除字段的属性定义上方
作用标识该字段为进行逻辑删除的字段
相关属性value:逻辑未删除值 delval:逻辑删除值

接下来就是跟线程有点关系的东西了,这就是学科之间的联动性啊,不对应该是一致性

来看看乐观锁,这就是我之前在操作系统实验里面有学到过的锁

一般我们会遇到一个问题,就是同一个活动可能会在不同服务器里同时执行,也就是并发,比如动车售票

那我们需要添加一个version的属性,首先在数据库里面给version设置默认值为1,长度为11

为了防止线程冲突,就会有类似逻辑

set version =newVersion where version=oldVersion
newVersion =version +1
oldVersion=newVersion

人话来说就是我要对version实现自增加1

那么我俩个线程在执行时,假如线程1执行,version会变成2,那么线程2在执行时就会发现version=2无法执行,从而保证了线程不会并发,唯一动作被执行

那么我们添加一下

@Data  
public class User {  
    private Long id;  
    private String name;  
    private String password;  
    private Integer age;  
    private String tel;  
    @TableLogic(value = "0", delval = "1")  
    private Integer deleted;  
    @Version  
    private Integer version;  
}

并在配置文件里面添加一下乐观锁拦截器

@Configuration  
public class MpConfig {  
    @Bean  
    public MybatisPlusInterceptor mpInterceptor() {  
        //1.定义Mp拦截器  
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();  
        //2.添加乐观锁拦截器  
        mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());  
        return mpInterceptor;  
    }  
}

做一个简单的案例,也就是俩个user对象对内容进行修改

@Test  
void testUpdate() {  
    User userA = userDao.selectById(1L); //version=1  
    User userB = userDao.selectById(1L); //version=1  
    userB.setName("Jackson");  
    userDao.updateById(userB);  //B修改完了之后,version=2  
    userA.setName("Person");  
    //A拿到的version是1,但现在的version已经是2了,那么A在执行 UPDATE ... WHERE version = 1时,就必然会失败  
    userDao.updateById(userA);    
}

就是这个,可以理解为userA和userB都拿到了1L这个对象,那么我userB执行setName后,这里version就自增等于2了,那么userA就没办法对version已经为2的1L进行修改了,这就保证了我们在同一时间内数据不会被两个用户更改而产生冲突

当然这里的updateById方法是能正常执行的

OKOKOK接下来就是最后一part了,就是这个代码生成器了(其实用起来很难受,但咱还是多少要学一下)

首先就是需要在maven里面把这个依赖配置一下,

<!--代码生成器-->  
        <dependency>  
            <groupId>com.baomidou</groupId>  
            <artifactId>mybatis-plus-generator</artifactId>  
            <version>3.4.1</version>  
        </dependency>  

        <!--velocity模板引擎-->  
        <dependency>  
            <groupId>org.apache.velocity</groupId>  
            <artifactId>velocity-engine-core</artifactId>  
            <version>2.3</version>  
        </dependency>

这里需要根据我们的版本进行灵活的变更
然后再编写一个引导类

@SpringBootApplication  
public class Mybatisplus04GeneratorApplication {  
    public static void main(String[] args) {  
        SpringApplication.run(Mybatisplus04GeneratorApplication.class, args);  
    }  

}

没错这个就是负责我们生成文件的启动器

然后就是

public class CodeGenerator {  
    public static void main(String[] args) {  
        //1.获取代码生成器的对象  
        AutoGenerator autoGenerator = new AutoGenerator();  

        //设置数据库相关配置  
        DataSourceConfig dataSource = new DataSourceConfig();  
        dataSource.setDriverName("com.mysql.cj.jdbc.Driver");  
        dataSource.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC");  
        dataSource.setUsername("root");  
        dataSource.setPassword("YOURPASSWORD");  
        autoGenerator.setDataSource(dataSource);  

        //设置全局配置  
        GlobalConfig globalConfig = new GlobalConfig();  
        globalConfig.setOutputDir(System.getProperty("user.dir")+"/项目名/src/main/java");    //设置代码生成位置  
        globalConfig.setOpen(false);    //设置生成完毕后是否打开生成代码所在的目录  
        globalConfig.setAuthor("Kyle");    //设置作者  
        globalConfig.setFileOverride(true);     //设置是否覆盖原始生成的文件  
        globalConfig.setMapperName("%sDao");    //设置数据层接口名,%s为占位符,指代模块名称  
        globalConfig.setIdType(IdType.ASSIGN_ID);   //设置Id生成策略  
        autoGenerator.setGlobalConfig(globalConfig);  

        //设置包名相关配置  
        PackageConfig packageInfo = new PackageConfig();  
        packageInfo.setParent("com.aaa");   //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径  
        packageInfo.setEntity("domain");    //设置实体类包名  
        packageInfo.setMapper("dao");   //设置数据层包名  
        autoGenerator.setPackageInfo(packageInfo);  

        //策略设置  
        StrategyConfig strategyConfig = new StrategyConfig();  
        strategyConfig.setInclude("tb_user");  //设置当前参与生成的表名,参数为可变参数  
        strategyConfig.setTablePrefix("tb_");  //设置数据库表的前缀名称,模块名 = 数据库表名 - 前缀名  例如: User = tb_user - tb_  
        strategyConfig.setRestControllerStyle(true);    //设置是否启用Rest风格  
        strategyConfig.setVersionFieldName("version");  //设置乐观锁字段名  
        strategyConfig.setLogicDeleteFieldName("deleted");  //设置逻辑删除字段名  
        strategyConfig.setEntityLombokModel(true);  //设置是否启用lombok  
        autoGenerator.setStrategy(strategyConfig);  
        //2.执行生成操作  
        autoGenerator.execute();  
    }  
}

这个就类似专门为代码生成器写的配置文件,当然这里面的乐死globalConfig可以用类似

global.setOutPutDir()
       .setOpen(false)
       .setAuthorf("me")
       ......

这么写,节省一点时间,下面那些同理

然后就需要我们自己去编写ftl文件对我们对于文件进行详细配置

运行那个负责生成的文件后,就可以生成我们需要的controller,service ,mapper,entity等文件

嗯,这就是全部了,从27到今天大概一周左右,MP的内容没有想象中的那么多,但是具体我掌     握得怎么样还得看我之后得使用,路漫漫其修远兮啊。
如果后续我有什么地方写错,我会再进行更新额,我也会常来复习这些内容的
还有就是,特别感谢我同学分享的资源和心得,这是他网站的链接 http://artsail.top/
文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇