Mybatis-Plus

目录

1.1 快速上手

1.2 配置日志

1.3 测试插入数据

1.4 测试更新数据

雪花算法(插曲)

2.1 核心功能—代码生成器 

2.2 核心功能—条件构造器

简单案例

3.1 拓展—配置主键自增

3.2 拓展—逻辑删除

说明

使用案例

3.3 拓展—自动填充创建时间、修改时间

4.1 插件—分页 

4.2 插件—乐观锁

4.3 插件—性能分析 

使用案例


快速开始 | MyBatis-Plus (baomidou.com)

1.1 快速上手

1.创建数据库,创建表

Mybatis-Plus

  • 建表sql
DROP TABLE IF EXISTS user;

CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);

DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

2.新建一个springboot项目

3.添加依赖

<dependencies>
        <!--数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1.tmp</version>
        </dependency>

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

4.application.properties

# mysql 5.xx
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/db2021
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

5.创建实体类pojo

package com.IT.mybatis.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

6.mapper接口

package com.IT.mybatis.mapper;

import com.IT.mybatis.pojo.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;

/**
 * 在对应的mapper上面 继承 基本的类 BaseMapper
 * 所有的CRUD操作都已经编写完成
 * 不需要再像mybatis一样编写映射文件
 */
@Repository
public interface Usermapper extends BaseMapper<User> {
}

7.主启动类

package com.IT.mybatis;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// 在 SpringBoot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹
@MapperScan("com.IT.mybatis.mapper")
@SpringBootApplication
public class SpringbootMybatisPlusApplication {

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

}

8.测试

package com.IT.mybatis;

import com.IT.mybatis.mapper.UserMapper;
import com.IT.mybatis.pojo.User;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class SpringbootMybatisPlusApplicationTests {
    // 继承了BaseMapper,父类中的方法都可以使用,当然,我们也可以编写自己的拓展方法
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        // UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件
        List<User> userList = userMapper.selectList(null);
        userList.forEach(System.out::println);
    }

    @Test
    void contextLoads() {
    }

}

测试结果:

User(id=1, name=Jone, age=18, email=test1@baomidou.com)
User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)
User(id=4, name=Sandy, age=21, email=test4@baomidou.com)
User(id=5, name=Billie, age=24, email=test5@baomidou.com)

通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!

从以上步骤中,我们可以看到集成MyBatis-Plus非常的简单,只需要引入 starter 工程,并配置 mapper 扫描路径即可!

1.2 配置日志

1.在application.properties文件中添加

# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2.控制台输出结果

Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
Property 'mapperLocations' was not specified.
 _ _   |_  _ _|_. ___ _ |    _ 
| | |\/|_)(_| | |_\  |_)||_|_\ 
     /               |         
                        3.3.1.tmp 
2021-11-20 14:14:06.157  INFO 3972 --- [           main] .m.SpringbootMybatisPlusApplicationTests : Started SpringbootMybatisPlusApplicationTests in 3.45 seconds (JVM running for 4.783)
----- selectAll method test ------
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@37c41ec0] was not registered for synchronization because synchronization is not active
2021-11-20 14:14:06.477  INFO 3972 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2021-11-20 14:14:06.778  INFO 3972 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
JDBC Connection [HikariProxyConnection@131532344 wrapping com.mysql.jdbc.JDBC4Connection@732f6050] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email FROM user 
==> Parameters: 
<==    Columns: id, name, age, email
<==        Row: 1, Jone, 18, test1@baomidou.com
<==        Row: 2, Jack, 20, test2@baomidou.com
<==        Row: 3, Tom, 28, test3@baomidou.com
<==        Row: 4, Sandy, 21, test4@baomidou.com
<==        Row: 5, Billie, 24, test5@baomidou.com
<==      Total: 5
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@37c41ec0]

1.3 测试插入数据

1.测试代码

    // 测试插入
    @Test
    public void testInsert(){
        User user=new User(null,"tom",99,"23424524@qq.com");
        int result=userMapper.insert(user);
        System.out.println(result);
        System.out.println(user);
    }

2.插入结果,id自动回填

1
User(id=1461942928325693442, name=tom, age=99, email=23424524@qq.com)

bug修复:在用单元测试的时候,总是向数据库中插入两条数据,如下图

Mybatis-Plus

在网上找了解决办法,是这样说的:单元测试时会先build进行编译,而build的时候会执行你项目中的所有加了@Test的方法 并且具体解决步骤如下,将这个勾选上,这是跳过测试的意思

Mybatis-Plus

再次用单元测试的时候就可以了

Mybatis-Plus

1.4 测试更新数据

1.测试更新代码

    // 测试更新
    @Test
    public void testUpdate(){
        User user=new User();
        user.setId(5L);
        user.setName("hello,mybatis-plus");
        // 参数是一个对象
        int i=userMapper.updateById(user);
        System.out.println(i);
    }

2.测试结果 

Mybatis-Plus

雪花算法(插曲)

SnowFlake是Twitter公司采用的一种算法,目的是在分布式系统中产生全局唯一且趋势递增的ID

组成部分(64bit)

1.第一位 占用1bit,其值始终是0,没有实际作用

2.时间戳 占用41bit,精确到毫秒,总共可以容纳约69年的时间

3.工作机器id 占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,做多可以容纳1024个节点

4.序列号 占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID

SnowFlake算法在同一毫秒内最多可以生成多少个全局唯一ID呢:: 同一毫秒的ID数量 = 1024 X 4096 = 4194304 

2.1 核心功能—代码生成器 

我写在下面这篇文章里了Mybatis—Plus代码自动生成器超详细讲解(3.5.1+版本)_****^_^****的博客-CSDN博客

2.2 核心功能—条件构造器

通过条件构造器构造复杂SQL,过滤、筛选数据

简单案例

1.测试代码

    @Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        // UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件
        QueryWrapper<User>wrapper=new QueryWrapper<>();
        // 查询条件:name不为空、email不为空、年龄大于12
        wrapper.isNotNull("name")
                .isNotNull("email")
                .ge("age",12);
        List<User> userList = userMapper.selectList(wrapper);
        userList.forEach(System.out::println);
    }

2.查询结果

 Preparing: SELECT id,name,age,email,create_time,update_time,version,deleted FROM user 
WHERE deleted=0 AND (name IS NOT NULL AND email IS NOT NULL AND age >= ?) 
==> Parameters: 12(Integer)
<==    Columns: id, name, age, email, create_time, update_time, version, deleted
<==        Row: 5, hello,mybatis-plus, 24, test5@baomidou.com, null, null, 1, 0
<==        Row: 1461947382575894531, tom, 99, 23424524@qq.com, null, null, 1, 0
<==        Row: 1461947382575894532, 测试更新, 99, 23424524@qq.com, 2021-11-20 18:18:03.0, 2021-11-25 15:04:53.0, 1, 0
<==      Total: 3

3.1 拓展—配置主键自增

1.实体类的属性上添加注解

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    
    @TableId(type = IdType.AUTO)
    private Long id;
    
    private String name;
    private Integer age;
    private String email;
}

2.在数据库连接工具中修改主键为自增

Mybatis-Plus

3.再次测试插入 

Mybatis-Plus

3.2 拓展—逻辑删除

说明

物理删除:从数据库中直接删除

逻辑删除:实际上只是数据失效,在数据库中没有被删除,当我们查询数据时,如果带上逻辑删除条件,那么被逻辑删除过的数据将不会被查询出来

只对自动注入的sql起效:

  • 插入: 不作限制
  • 查找: 追加where条件过滤掉已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
  • 更新: 追加where条件防止更新到已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
  • 删除: 转变为 更新

例如:

  • 删除: update user set deleted=1 where id = 1 and deleted=0
  • 查找: select id,name,deleted from user where deleted=0

字段类型支持说明:

  • 支持所有数据类型(推荐使用 Integer,Boolean,LocalDateTime)
  • 如果数据库字段使用datetime,逻辑未删除值和已删除值支持配置为字符串null,另一个值支持配置为函数来获取值如now()

附录:

  • 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除
  • 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示

使用案例

1.数据库中增加字段

Mybatis-Plus

2.pojo实体类

    @TableLogic // 逻辑删除
    private Integer deleted;

3.application.properties文件

# 配置逻辑删除
# 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
# mybatis-plus.global-config.db-config.logic-delete-field=deleted
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0

4.测试代码

    // 测试逻辑删除
    @Test
    public void testDeleteBatchId(){
        userMapper.deleteBatchIds(Arrays.asList(3L,4L));
    }

5.数据库结果,deleted字段值变为1

Mybatis-Plus

6. 逻辑删除下,测试查询操作时会自动拼接查询条件,deleted=1的数据将不会被查询出来

==>  Preparing: SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE deleted=0 
==> Parameters: 
<==    Columns: id, name, age, email, create_time, update_time, version, deleted
<==        Row: 5, hello,mybatis-plus, 24, test5@baomidou.com, null, null, 1, 0
<==        Row: 1461947382575894531, tom, 99, 23424524@qq.com, null, null, 1, 0
<==        Row: 1461947382575894532, 更新了数据, 99, 23424524@qq.com, 2021-11-20 18:18:03.0, 2021-11-20 18:28:47.0, 1, 0

3.3 拓展—自动填充创建时间、修改时间

根据阿里巴巴开发手册,在数据库表中,对数据的创建、修改操作要求记录下创建时间、修改时间,并且由于数据量庞大,手工添加肯定是不行的,肯定需要自动填充,下面我们来看怎么实现这个功能?

1.在表中新增字段:create_time、update_time

Mybatis-Plus

2.实体类:注解填充字段 @TableField(.. fill = FieldFill.INSERT)

package com.IT.mybatis.pojo;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @TableId(type = IdType.AUTO)
    private Long id;

    private String name;
    private Integer age;
    private String email;
    // 字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

3.自定义实现类MyMetaObjectHandler并继承MetaObjectHandler

package com.IT.mybatis.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    // 插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
    }
    // 更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
    }
}

4.测试插入操作

    @Test
    public void testInsert() {
        User user = new User((Long)null, "tom", 99, "23424524@qq.com", (LocalDateTime)null, (LocalDateTime)null);
        int result = this.userMapper.insert(user);
        System.out.println(result);
        System.out.println(user);
    }

结果:

1
User(id=1461947382575894532, name=tom, age=99, email=23424524@qq.com, createTime=2021-11-20T18:18:03.382, updateTime=null)

刷新数据库

Mybatis-Plus

5.测试更新操作

    // 测试更新
    @Test
    public void testUpdate(){
        User user=new User();
        user.setId(1461947382575894532L);
        user.setName("更新了数据");
        // 参数是一个对象
        int i=userMapper.updateById(user);
        System.out.println(i);
    }

后台输出1,更新成功!然后看一下数据库

Mybatis-Plus

注意事项:

  • 填充原理是直接给entity的属性设置值!!!
  • 注解则是指定该属性在对应情况下必有值,如果无值则入库会是null
  • MetaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null则不填充
  • 字段必须声明TableField注解,属性fill选择对应策略,该声明告知Mybatis-Plus需要预留注入SQL字段
  • 填充处理器MyMetaObjectHandler在 Spring Boot 中需要声明@Component@Bean注入
  • 要想根据注解FieldFill.xxx字段名以及字段类型来区分必须使用父类的strictInsertFill或者strictUpdateFill方法
  • 不需要根据任何来区分可以使用父类的fillStrategy方法 

4.1 插件—分页 

PaginationInnerInterceptor

支持的数据库

  • mysql,oracle,db2,h2,hsql,sqlite,postgresql,sqlserver,Phoenix,Gauss ,clickhouse,Sybase,OceanBase,Firebird,cubrid,goldilocks,csiidb

1.在配置类中添加组件

    // 旧版
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 设置请求的页面大于最大页后操作, true 调回到首页;false 继续请求 
        // 默认是false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }

2.测试代码

    // 测试分页查询
    @Test
    public void testPage(){
        // 页数:1,每页数据条数:5
        Page<User>page=new Page<>(1,5);
        userMapper.selectPage(page,null);
        page.getRecords().forEach(System.out::println);
    }

3.测试结果

<==        Row: 1, 22222211, 18, 99999999@qq.com, null, 2021-11-20 19:00:27.0, 4
<==        Row: 2, Jack, 20, test2@baomidou.com, null, null, 1
<==        Row: 3, Tom, 28, test3@baomidou.com, null, null, 1
<==        Row: 4, Sandy, 21, test4@baomidou.com, null, null, 1
<==        Row: 5, hello,mybatis-plus, 24, test5@baomidou.com, null, null, 1

查询第二页

    // 测试分页查询
    @Test
    public void testPage(){
        // 页数:2,每页数据条数:5
        Page<User>page=new Page<>(2,5);
        userMapper.selectPage(page,null);
        page.getRecords().forEach(System.out::println);
    }

查询结果 

<==        Row: 1461947382575894531, tom, 99, 23424524@qq.com, null, null, 1
<==        Row: 1461947382575894532, 更新了数据, 99, 23424524@qq.com, 2021-11-20 18:18:03.0, 2021-11-20 18:28:47.0, 1
<==      Total: 2

4.2 插件—乐观锁

OptimisticLockerInnerInterceptor

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

乐观锁配置步骤

1.表中增加version字段

Mybatis-Plus

2.实体类

    @Version // 乐观锁注解
    private Integer version;

说明:

  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 整数类型下 newVersion = oldVersion + 1
  • newVersion 会回写到 entity 中
  • 仅支持 updateById(id) 与 update(entity, wrapper) 方法
  • 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!

3.注册组件

package com.IT.mybatis.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 配置类
@Configuration
// 在 SpringBoot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹
@MapperScan("com.IT.mybatis.mapper")
public class MyBatisPlusConfig {
    // 注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

4.测试乐观锁

    // 测试乐观锁
    @Test 
    public void testOptimisticLocker(){
        // 1.查询用户信息
        User user=userMapper.selectById(1L);
        // 2.修改用户信息
        user.setName("zhangsan");
        user.setEmail("99999999@qq.com");
        // 3.执行更新操作
        userMapper.updateById(user);
    }

可以看到更新成功

Mybatis-Plus

同时我们可以模拟一下乐观锁更新失败的情况

    // 测试乐观锁
    @Test
    public void testOptimisticLocker(){
        // 线程1
        // 查询用户信息
        User user1=userMapper.selectById(1L);
        // 修改用户信息
        user1.setName("111111");
        user1.setEmail("99999999@qq.com");
        
        // 线程2
        // 查询用户信息
        User user2=userMapper.selectById(1L);
        // 修改用户信息
        user2.setName("222222");
        user2.setEmail("99999999@qq.com");
        
        // 执行更新操作: 本来是1先执行的,但是这时候被2抢先了
        userMapper.updateById(user2);
        userMapper.updateById(user1);
    }

1执行更新操作时的后台日志

==>  Preparing: UPDATE user SET name=?, age=?, email=?, update_time=?, version=? WHERE id=? AND version=? 
==> Parameters: 111111(String), 18(Integer), 99999999@qq.com(String), 2021-11-20T19:00:27(LocalDateTime), 3(Integer), 1(Long), 2(Integer)
<==    Updates: 0

在数据库中可以看到2更新成功了,而1去执行更新操作的时候,由于版本号被修改,版本对应不上,导致更新失败! 

4.3 插件—性能分析 

性能分析拦截器,用于输出每条SQL语句及其执行时间

新版本中推荐使用第三方拓展 执行SQL分析打印 功能

使用案例

1.引入依赖

2.application.yml

  • 关键点1:url需要加上p6spy 固定的是jdbc:p6spy:数据库名…...
  • 关键点2:driver-class-name指定的是p6spy的驱动
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:p6spy:mysql://localhost:3306/db2021
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver

3.spy.properties

  • 关键点,一定要通过driverlist指定真实的JDBC驱动
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
# appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
# driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
# 真实JDBC driver
driverlist=com.mysql.jdbc.Driver

4.测试

Mybatis-Plus

再测试一下更新操作的用时

Mybatis-Plus

上一篇:mybatis-plus查询,部分字段没有值


下一篇:mybatis plus条件构造器