IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Mybatis-Plus详解 -> 正文阅读

[Java知识库]Mybatis-Plus详解

目录

1. Mybatis-Plus概念

1.1 Mybatis-Plus介绍

1.2 特性

1.3 架构

2. Mybatis-Plus快速??

2.1 安装

2.2 创建数据库以及表

2.3 创建?程

2.4 Mybatis + MP

2.5 Spring + Mybatis + MP

2.6 SpringBoot + Mybatis + MP

3. 通?CRUD

3.1 插?操作

3.2 更新操作

3.3 删除操作

3.4 查询操作

3.4.1、selectById

3.4.2、selectBatchIds

3.4.3、selectOne

3.4.4、selectCount

3.4.5、selectList

3.4.6、selectPage

3.5 SQL注?的原理

4. 配置

4.1、基本配置

4.1.1、configLocation

4.1.2、mapperLocations

4.1.3、typeAliasesPackage

4.2、进阶配置

4.2.1、mapUnderscoreToCamelCase

4.2.2、cacheEnabled

4.3、DB 策略配置

4.3.1、idType

4.3.2、tablePrefix

5. 条件构造器

5.1、allEq

5.1.1、说明

5.1.2、测试?例

5.2、基本?较操作

5.3、模糊查询

5.4、排序

5.5、逻辑查询

5.6、select

6. ActiveRecord

6.1、开启AR之旅

6.2、根据主键查询

6.3、新增数据

6.4、更新操作

6.5、删除操作

6.6、根据条件查询

7. 插件

7.1、mybatis的插件机制

7.2、执?分析插件

7.3、性能分析插件

7.4、乐观锁插件

7.4.1、主要适?场景

7.4.2、插件配置

7.4.3、注解实体字段

7.4.5、特别说明

8. Sql 注?器

8.1、编写MyBaseMapper

8.2、编写MySqlInjector

8.3、编写FindAll

8.4、注册到Spring容器

8.5、测试

9. ?动填充功能

9.1、添加@TableField注解

9.2、编写MyMetaObjectHandler

9.3、测试

10. 逻辑删除

10.1、修改表结构

10.2、配置

10.3、测试

11. 代码?成器

12. MybatisX 快速开发插件


1. Mybatis-Plus概念

1.1 Mybatis-Plus介绍

官?:Redirect
MyBatis-Plus(简称 MP)是?个 MyBatis 的增强?具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提
?效率??。

1.2 特性

  • ?侵?:只做增强不做改变,引?它不会对现有?程产?影响,如丝般顺滑。
  • 损耗?:启动即会?动注?基本 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 操作智能分析阻断,也可?定义拦截规则,预防误操作。

1.3 架构

架构.png


2. Mybatis-Plus快速??

2.1 安装

全新的 MyBatis-Plus 3.0 版本基于 JDK8,提供了 lambda 形式的调?,所以安装集成 MP3.0 要求如下:

  • JDK 8+
  • Maven or Gradle

Spring Boot
Maven:

<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>mybatis-plus-boot-starter</artifactId>
   <version>3.4.0</version>
</dependency>

Spring MVC
Maven:

<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>mybatis-plus</artifactId>
   <version>3.4.0</version>
</dependency>

对于Mybatis整合MP有常常有三种?法,分别是Mybatis+MP、Spring+Mybatis+MP、SpringBoot+Mybatis+MP。

2.2 创建数据库以及表

-- 创建测试表
DROP TABLE IF EXISTS tb_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) );

-- 插?测试数据
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.3 创建?程

创建一个Maven工程 com.zm.mp
导?依赖:

 <dependencies>
        <!-- mybatis-plus插件依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.1.1</version>
        </dependency>

        <!--Mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!--连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.11</version>
        </dependency>

        <!--简化bean代码的?具包-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

2.4 Mybatis + MP

下?演示,通过纯Mybatis与Mybatis-Plus整合。
创建?Module: zm-mybatis-plus-simple

    <?xml version="1.0" encoding="UTF-8" ?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                                 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>zm-mybatis-plus</artifactId>
            <groupId>com.zm.mp</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>

        <modelVersion>4.0.0</modelVersion>
        <artifactId>zm-mybatis-plus-simple</artifactId>
    </project>

引入log4j.properties:

log4j.rootLogger=DEBUG,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n

Mybatis实现查询User
第?步,编写mybatis-config.xml?件:


    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <properties resource="jdbc.properties"></properties>

        <!--environments: 运?环境-->
        <environments default="development">
            <environment id="development">
                <!--当前的事务事务管理器是JDBC-->
                <transactionManager type="JDBC"></transactionManager>
                <!--数据源信息 POOLED:使?mybatis的连接池-->
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>

        <!--引?映射配置?件-->
        <mappers>
            <mapper resource="mapper/UserMapper.xml"></mapper>
        </mappers>
    </configuration>

第?步,编写User实体对象:(这?使?lombok进?了进化bean操作)

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

第三步,编写UserMapper接?:

public interface UserMapper {
 
 List<User> findAll();
}

第四步,编写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.zm.mapper.UserMapper">
        <!-- 查询所有 -->
        <select id="findAll" resultType="com.zm.pojo.User">
            select * from user
        </select>
    </mapper>

第五步,编写TestMybatis测试?例:

public class MPTest {
    @Test
    public void test1() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> all = mapper.findAll();
        for (User user : all) {
            System.out.println(user);
        }
    }
}

测试结果:

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)

注:如果实体类名称和表名称不?致,可以在实体类上添加注解@TableName("指定数据库表名")

Mybatis+MP实现查询User
第?步,将UserMapper继承BaseMapper,将拥有了BaseMapper中的所有?法:

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zm.pojo.User;

public interface UserMapper extends BaseMapper<User> {
}

第?步,使?MP中的MybatisSqlSessionFactoryBuilder进程构建:

@Test
public void test2()throws IOException{
        InputStream resourceAsStream=Resources.getResourceAsStream("sqlMapConfig.xml");
        //这?使?的是MP中的MybatisSqlSessionFactoryBuilder
        SqlSessionFactory sqlSessionFactory=new MybatisSqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession=sqlSessionFactory.openSession();
        UserMapper mapper=sqlSession.getMapper(UserMapper.class);
        // 可以调?BaseMapper中定义的?法
        List<User> all=mapper.selectList(null);
        for(User user:all){
           System.out.println(user);
        }
}

测试:

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)

注:如果实体类名称和表名称不?致,可以在实体类上添加注解@TableName("指定数据库表名")。
简单说明:

  • 由于使?了 MybatisSqlSessionFactoryBuilder进?了构建,继承的BaseMapper中的?法就载?到了SqlSession中,所以就可以直接使?相关的?法;

2.5 Spring + Mybatis + MP

引?了Spring框架,数据源、构建等?作就交给了Spring管理。
创建?Module

<?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>zm-mybatis-plus</artifactId>
        <groupId>com.zm.mp</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>zm-mybatis-plus-spring</artifactId>
    <properties>
        <spring.version>5.1.6.RELEASE</spring.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>

实现查询User
第?步,编写jdbc.properties:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mp?serverTimezone=GMT%2B8&useSSL=false
jdbc.username=root
jdbc.password=root

第?步,编写applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation=" http://www.springframework.org/schema/beans
                                http://www.springframework.org/schema/beans/spring-beans.xsd
                                http://www.springframework.org/schema/context
                                http://www.springframework.org/schema/context/spring-context.xsd">
        <!--引?properties-->
        <context:property-placeholder location="classpath:jdbc.properties"/>
        <!--dataSource数据源-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </bean>

        <!--这?使?MP提供的sqlSessionFactory,完成spring与mp的整合-->
        <bean id="sqlSessionFactory"
              class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
        </bean>

        <!--扫描mapper接?,使?的依然是mybatis原?的扫描器-->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.zm.mapper"/>
        </bean>
    </beans>

第三步,编写User对象以及UserMapper接?:

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


public interface UserMapper extends BaseMapper<User> {
 List<User> findAll();
}

第四步,编写测试?例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class TestSpringMP {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void test2() throws IOException {
        List<User> users = this.userMapper.selectList(null);
        for (User user : users) {
            System.out.println(user);
        }
    }
}

2.6 SpringBoot + Mybatis + MP

使?SpringBoot将进?步的简化MP的整合,需要注意的是,由于使?SpringBoot需要继承parent,所以需要重新
创建?程,并不是创建?Module。
创建SpringBoot?程并导?对应依赖

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

        <!--简化代码的?具包-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--mybatis-plus的springboot?持-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.1</version>
        </dependency>

        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

引入log4j.properties:

log4j.rootLogger=DEBUG,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n

编写application.properties:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

编写pojo:

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

编写mapper:

public interface UserMapper extends BaseMapper<User> {
}

编写启动类:

package com.zm.mp;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
@MapperScan("com.zm.mp.mapper") //设置mapper接?的扫描包
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

编写测试?例测试:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelect() {
        List<User> userList = userMapper.selectList(null);
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

结果:

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)

3. 通?CRUD

通过前?的学习,我们了解到通过继承BaseMapper就可以获取到各种各样的单表操作,接下来我们将详细讲解这
些操作。

3.1 插?操作

?法定义

/**
 * 插??条记录
 *
 * @param entity 实体对象.
 */
 int insert(T entity);

测试?例

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testInsert(){
        User user = new User();
        user.setAge(18);
        user.setEmail("123456@qq.com");
        user.setName("张三");

        //返回的result是受影响的?数,并不是?增后的id
        int result = userMapper.insert(user);
        System.out.println(result);
        System.out.println(user.getId());
    }
}

结果:

1
1318744682116739074

通过数据库可以看到,数据已经写?到了数据库,但是,id的值不正确,我们期望的是数据库?增?,实际是MP?成了id的值写?到了数据库。
如何设置id的?成策略呢?
MP?持的id策略:

package com.baomidou.mybatisplus.annotation;
import lombok.Getter;
/**
 * ?成ID类型枚举类
 *
 * @author zm
 * @since 2021-11-10
 */
@Getter
public enum IdType {
    /**
     * 数据库ID?增
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型
     */
    NONE(1),
    /**
     * ?户输?ID
     * <p>该类型可以通过??注册?动填充插件进?填充</p>
     */
    INPUT(2),
    /* 以下3种类型、只有当插?对象ID 为空,才?动填充。 */
    /**
     * 全局唯?ID (idWorker)
     */
    ID_WORKER(3),
    /**
     * 全局唯?ID (UUID)
     */
    UUID(4),
    /**
     * 字符串全局唯?ID (idWorker 的字符串表示)
     */
    ID_WORKER_STR(5);
    private final int key;
    IdType(int key) {
        this.key = key;
    }
}

修改User对象:

package com.zm.mp.pojo;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("tb_user")
public class User {
    @TableId(type = IdType.AUTO) //指定id类型为?增?
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;
}

最后测试发现数据插?成功,id的值也是正确的。

@TableField
在MP中通过@TableField注解可以指定字段的?些属性,常常解决的问题有2个:

1、对象中的属性名和字段名不?致的问题(?驼峰)
2、对象中的属性字段在表中不存在的问题

使?:

其他?法,如?字段不加?查询字段:


效果:

3.2 更新操作

在MP中,更新操作有2种,?种是根据id更新,另?种是根据条件更新。
根据id更新
?法定义:

 /**
 * 根据 ID 修改
 *
 * @param entity 实体对象
 */
 int updateById(@Param(Constants.ENTITY) T entity);

测试:

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
   @Autowired
   private UserMapper userMapper;

   @Test
   public void testUpdateById() {
     User user = new User();
     user.setId(5L); //主键
     user.setAge(21); //更新的字段
     //根据id更新,更新不为null的字段
     this.userMapper.updateById(user);
  }
}

根据条件更新
?法定义:

/**
 * 根据 whereEntity 条件,更新记录
 *
 * @param entity 实体对象 (set 条件值,可以为 null)
 * @param updateWrapper 实体对象封装操作类(可以为 null,??的 entity ?于?成 where 语句)
 */
 int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T>
updateWrapper);

测试?例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import net.minidev.json.writer.UpdaterMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;
    
    @Test
    public void testUpdate() {
        User user = new User();
        user.setAge(22); //更新的字段
        //更新的条件
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", 5);
        //执?更新操作
        int result = this.userMapper.update(user, wrapper);
        System.out.println("result = " + result);
    }
}

或者,通过UpdateWrapper进?更新:

@Test
public void testUpdate(){
        //更新的条件以及字段
        UpdateWrapper<User> wrapper=new UpdateWrapper<>();
        wrapper.eq("id",5).set("age",23);
        //执?更新操作
        int result=this.userMapper.update(null,wrapper);
        System.out.println("result = "+result);
}

均可达到更新的效果。

3.3 删除操作

deleteById
?法定义:

/**
* 根据 ID 删除
*
* @param id 主键ID
*/
int deleteById(Serializable id);

测试?例:

package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testDeleteById() {
        //执?删除操作
        int result = this.userMapper.deleteById(5L);
        System.out.println("result = " + result);
    }
}

deleteByMap
?法定义:

 /**
 * 根据 columnMap 条件,删除记录
 *
 * @param columnMap 表字段 map 对象
 */
 int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

测试?例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.HashMap;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testDeleteByMap() {
        Map<String, Object> columnMap = new HashMap<>();
        columnMap.put("age", 23);
        columnMap.put("name", "billie");
        //将columnMap中的元素设置为删除的条件,多个之间为and关系
        int result = this.userMapper.deleteByMap(columnMap);
        System.out.println("result = " + result);
    }
}

delete
?法定义:

/**
* 根据 entity 条件,删除记录
*
* @param wrapper 实体对象封装操作类(可以为 null)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);

测试?例:

package com.lagou.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.HashMap;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testDeleteByMap() {
        User user = new User();
        user.setAge(20);
        user.setName("billie");
        //将实体对象进?包装,包装为操作条件
        QueryWrapper<User> wrapper = new QueryWrapper<>(user);
        int result = this.userMapper.delete(wrapper);
        System.out.println("result = " + result);
    }
}

deleteBatchIds
?法定义:

 /**
 * 删除(根据ID 批量删除)
 *
 * @param idList 主键ID列表(不能为 null 以及 empty)
 */
 int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable>idList);

测试?例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Arrays;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testDeleteByMap() {
        //根据id集合批量删除
        int result = this.userMapper.deleteBatchIds(Arrays.asList(1L, 10L, 20L));
        System.out.println("result = " + result);
    }
}

3.4 查询操作

MP提供了多种查询操作,包括根据id查询、批量查询、查询单条数据、查询列表、分?查询等操作。

3.4.1、selectById

?法定义:

 /**
 * 根据 ID 查询
 *
 * @param id 主键ID
 */
 T selectById(Serializable id);

测试?例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectById() {
        //根据id查询数据
        User user = this.userMapper.selectById(2L);
        System.out.println("result = " + user);
    }
}

结果:

result = User(id=2, name=Jack, age=20, email=test2@baomidou.com)

3.4.2、selectBatchIds

?法定义:

/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable>idList);

测试?例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Arrays;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectBatchIds() {
        //根据id集合批量查询
        List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 10L));
        for (User user : users) {
            System.out.println(user);
        }
    }
}

结果:

User(id=2, name=Jack, age=20, email=test2@baomidou.com)
User(id=3, name=Tom, age=28, email=test3@baomidou.com)

3.4.3、selectOne

?法定义:

/**
* 根据 entity 条件,查询?条记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

测试用例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectOne() {
        QueryWrapper<User> wrapper = new QueryWrapper<User>();
        wrapper.eq("name", "jack");
        //根据条件查询?条数据,如果结果超过?条会报错
        User user = this.userMapper.selectOne(wrapper);
        System.out.println(user);
    }
}

结果:

User(id=2, name=Jack, age=20, email=test2@baomidou.com)

3.4.4、selectCount

?法定义:

/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

测试用例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectCount() {
        QueryWrapper<User> wrapper = new QueryWrapper<User>();
        wrapper.gt("age", 23); //年龄?于23岁
        //根据条件查询数据条数
        Integer count = this.userMapper.selectCount(wrapper);
        System.out.println("count = " + count);
    }
}
}

结果:

count = 2

3.4.5、selectList

?法定义:

/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

测试用例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectList() {
        QueryWrapper<User> wrapper = new QueryWrapper<User>();
        wrapper.gt("age", 23); //年龄?于23岁
        //根据条件查询数据
        List<User> users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println("user = " + user);
        }
    }
}

结果:

user = User(id=3, name=Tom, age=28, email=test3@baomidou.com)
user = User(id=5, name=Billie, age=24, email=test5@baomidou.com)

3.4.6、selectPage

?法定义:

/**
* 根据 entity 条件,查询全部记录(并翻?)
*
* @param page 分?查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

配置分页插件:

package com.zm.mp;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@MapperScan("com.zm.mp.mapper") //设置mapper接?的扫描包
public class MybatisPlusConfig {
    /**
     * 分?插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

测试用例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectPage() {
        QueryWrapper<User> wrapper = new QueryWrapper<User>();
        wrapper.gt("age", 20); //年龄?于20岁
        Page<User> page = new Page<>(1, 1);
        //根据条件查询数据
        IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
        System.out.println("数据总条数:" + iPage.getTotal());
        System.out.println("总?数:" + iPage.getPages());
        List<User> users = iPage.getRecords();
        for (User user : users) {
            System.out.println("user = " + user);
        }
    }
}

3.5 SQL注?的原理

前?我们已经知道,MP在启动后会将BaseMapper中的?系列的?法注册到meppedStatements中,那么究竟是
如何注?的呢?流程?是怎么样的?下?我们将?起来分析下。
在MP中,ISqlInjector负责SQL的注??作,它是?个接?,AbstractSqlInjector是它的实现类,实现关系如下:

在AbstractSqlInjector中,主要是由inspectInject()?法进?注?的,如下:

@Override
public void inspectInject(MapperBuilderAssistant builderAssistant,Class<?>
mapperClass){
        Class<?> modelClass=extractModelClass(mapperClass);
        if(modelClass!=null){
          String className=mapperClass.toString();
          Set<String> mapperRegistryCache=GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());
            if(!mapperRegistryCache.contains(className)){
                List<AbstractMethod> methodList=this.getMethodList();
              if(CollectionUtils.isNotEmpty(methodList)){
                TableInfo tableInfo=TableInfoHelper.initTableInfo(builderAssistant,modelClass);
               // 循环注??定义?法
                methodList.forEach(m->m.inject(builderAssistant,mapperClass,modelClass,tableInfo));
              }else{
                   logger.debug(mapperClass.toString()+", No effective injection method was found.");
              }
                   mapperRegistryCache.add(className);
            }
        }
}

在实现?法中, methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass,tableInfo)); 是关键,循环遍历?法,进?注?。
最终调?抽象?法injectMappedStatement进?真正的注?:

/**
 * 注??定义 MappedStatement
 *
 * @param mapperClass mapper 接?
 * @param modelClass mapper 泛型
 * @param tableInfo 数据库表反射信息
 * @return MappedStatement
 */
 public abstract MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo);

查看该?法的实现:

以SelectById为例查看:

public class SelectById extends AbstractMethod {
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?>modelClass, TableInfo tableInfo) {
        SqlMethod sqlMethod = SqlMethod.LOGIC_SELECT_BY_ID;
        SqlSource sqlSource = new RawSqlSource(configuration,
                        String.format(sqlMethod.getSql(),
                        sqlSelectColumns(tableInfo, false),
                        tableInfo.getTableName(), tableInfo.getKeyColumn(),
                        tableInfo.getKeyProperty(),
                        tableInfo.getLogicDeleteSql(true, false)), Object.class);
        return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, modelClass, tableInfo);
    }
}

可以看到,?成了SqlSource对象,再将SQL通过addSelectMappedStatement?法添加到meppedStatements
中。


4. 配置

在MP中有?量的配置,其中有?部分是Mybatis原?的配置,另?部分是MP的配置,详情:https://mybatis.plus/config/
下?我们对常?的配置做讲解。

4.1、基本配置

4.1.1、configLocation

MyBatis 配置?件位置,如果有单独的 MyBatis 配置,请将其路径配置到 configLocation 中。 MyBatisConfiguration 的具体内容请参考MyBatis 官??档
Spring Boot:

mybatis-plus.config-location = classpath:mybatis-config.xml

Spring MVC:

<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
     <property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>

4.1.2、mapperLocations

MyBatis Mapper 所对应的 XML ?件位置,如果您在 Mapper 中有?定义?法(XML 中有?定义实现),需要进
?该配置,告诉 Mapper 所对应的 XML ?件位置。
Spring Boot:

mybatis-plus.mapper-locations = classpath*:mybatis/*.xml

Spring MVC:

<bean id="sqlSessionFactory"
      class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
   <property name="mapperLocations" value="classpath*:mybatis/*.xml"/>
</bean>

Maven 多模块项?的扫描路径需以 classpath: classpath: 开头 (即加载多个 jar 包下的 XML ?件)。
测试:
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.zm.mp.mapper.UserMapper">
        <select id="findById" resultType="com.zm.mp.pojo.User">
            select * from tb_user where id = #{id}
        </select>
    </mapper>
package com.zm.mp.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zm.mp.pojo.User;

public interface UserMapper extends BaseMapper<User> {
    User findById(Long id);
}

测试用例 :

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest

public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testSelectPage() {
        User user = this.userMapper.findById(2L);
        System.out.println(user);
    }
}

运行结果:

4.1.3、typeAliasesPackage

MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML ?件中可以直接
使?类名,?不?使?全限定的类名(即 XML 中调?的时候不?包含包名)。
Spring Boot:

mybatis-plus.type-aliases-package = com.zm.mp.pojo

Spring MVC:

<bean id="sqlSessionFactory"
      class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <property name="typeAliasesPackage" value="com.baomidou.mybatisplus.samples.quickstart.entity"/>
</bean>

4.2、进阶配置

本部分(Configuration)的配置?都为 MyBatis 原??持的配置,这意味着您可以通过 MyBatis XML 配置?件的
形式进?配置。

4.2.1、mapUnderscoreToCamelCase

  • 类型: boolean
  • 默认值: true

是否开启?动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java
属性名 aColumn(驼峰命名) 的类似映射。

注意:
此属性在 MyBatis 中原默认值为 false,在 MyBatis-Plus 中,此属性也将?于?成最终的 SQL 的 select
body
如果您的数据库命名符合规则?需使? @TableField 注解指定数据库字段名

示例(SpringBoot):

#关闭?动驼峰映射,该参数不能和mybatis-plus.config-location同时存在
mybatis-plus.configuration.map-underscore-to-camel-case=false

4.2.2、cacheEnabled

  • 类型: boolean
  • 默认值: true

全局地开启或关闭配置?件中的所有映射器已经配置的任何缓存,默认为 true。
示例:

mybatis-plus.configuration.cache-enabled=false

4.3、DB 策略配置

4.3.1、idType

  • 类型: com.baomidou.mybatisplus.annotation.IdType
  • 默认值: ID_WORKER

全局默认主键类型,设置后,即可省略实体对象中的@TableId(type = IdType.AUTO)配置。
示例:
SpringBoot:

mybatis-plus.global-config.db-config.id-type=auto

SpringMVC:

<!--这?使?MP提供的sqlSessionFactory,完成了Spring与MP的整合-->
    <bean id="sqlSessionFactory"
          class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="globalConfig">
            <bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
                <property name="dbConfig">
                    <bean
                            class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
                        <property name="idType" value="AUTO"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

4.3.2、tablePrefix

  • 类型: String
  • 默认值: null

表名前缀,全局配置后可省略@TableName()配置。
SpringBoot:

mybatis-plus.global-config.db-config.table-prefix=tb_

SpringMVC:

 <bean id="sqlSessionFactory"
          class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="globalConfig">
            <bean class="com.baomidou.mybatisplus.core.config.GlobalConfig">
                <property name="dbConfig">
                    <bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
                        <property name="idType" value="AUTO"/>
                        <property name="tablePrefix" value="tb_"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

5. 条件构造器

在MP中,Wrapper接?的实现类关系如下:

可以看到,AbstractWrapper和AbstractChainWrapper是重点实现,接下来我们重点学习AbstractWrapper以及其?类。

说明:
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的?类?于?成 sql 的 where 条件, entity 属性也?于?成 sql 的 where 条件。
注意: entity ?成的 where 条件与 使?各个 api ?成的 where 条件没有任何关联?为

官??档地址:mybatis.plus

5.1、allEq

5.1.1、说明

allEq(Map<R, V> params)allEq(Map<R, V> params, boolean null2IsNull)allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
  • 全部eq(或个别isNull)

个别参数说明:
params : key 为数据库字段名, value 为字段值
null2IsNull : 为 true 则在 map 的 value 为 null 时调? isNull ?法,为 false 时则忽略 value 为 null 的

  • 例1: allEq({id:1,name:"?王",age:null}) ---> id = 1 and name = '?王' and age is null
  • 例2: allEq({id:1,name:"?王",age:null}, false) ---> id = 1 and name = '?王'
allEq(BiPredicate<R, V> filter, Map<R, V> params)allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)allEq(boolean condition, BiPredicate<R, V> filter,
Map<R, V> params, boolean null2IsNull)

个别参数说明:
filter : 过滤函数,是否允许字段传??对条件中
params 与 null2IsNull : 同上
allEq(Map<R, V> params)allEq(Map<R, V> params, boolean null2IsNull)allEq(boolean
condition, Map<R, V> params, boolean null2IsNull)
allEq(BiPredicate<R, V> filter, Map<R, V> params)allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)allEq(boolean condition, BiPredicate<R, V> filter,
Map<R, V> params, boolean null2IsNull)

  • 例1: allEq((k,v) -> k.indexOf("a") > 0, {id:1,name:"?王",age:null}) ---> name = '? 王' and age is null
  • 例2: allEq((k,v) -> k.indexOf("a") > 0, {id:1,name:"?王",age:null}, false) ---> name= '?王'

5.1.2、测试?例

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testWrapper() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //设置条件
        Map<String, Object> params = new HashMap<>();
        params.put("name", "jack");
        params.put("age", "20");
        // wrapper.allEq(params);//SELECT * FROM tb_user WHERE password IS NULL AND name= ? AND age = ?
        // wrapper.allEq(params,false); //SELECT * FROM tb_user WHERE name = ? AND age = ?
        // wrapper.allEq((k, v) -> (k.equals("name") || k.equals("age")),params);
        // SELECT * FROM tb_user WHERE name = ? AND age = ?
        List<User> users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }
}

5.2、基本?较操作

  • eq
    -- 等于 =
  • ne
    -- 不等于 <>
  • gt
    -- ?于 >
  • ge
    -- ?于等于 >=
  • lt
    -- ?于 <
  • le
    -- ?于等于 <=
  • between
    -- BETWEEN 值1 AND 值2
  • notBetween
    -- NOT BETWEEN 值1 AND 值2
  • in
    -- 字段 IN (value.get(0), value.get(1), ...)
  • notIn
    -- 字段 NOT IN (v0, v1, ...)

测试?例:

package com.zm.mp;

import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testWrapper() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //SELECT id,name,age,email FROM tb_user WHERE password = ? AND age >= ? AND name IN (?,?,?)
        wrapper.eq("email", "test2@baomidou.com")
                .ge("age", 20)
                .in("name", "jack", "jone", "tom");

        List<User> users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }
}

5.3、模糊查询

  • like
    -- LIKE '%值%'
    -- 例: like("name", "王") ---> name like '%王%'
  • notLike
    -- NOT LIKE '%值%'
    -- 例: notLike("name", "王") ---> name not like '%王%'
  • likeLeft
    -- LIKE '%值' 例: likeLeft("name", "王") ---> name like '%王'
  • likeRight
    -- LIKE '值%'
    -- 例: likeRight("name", "王") ---> name like '王%'

测试?例:

package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testWrapper() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //SELECT id,user_name,password,name,age,email FROM tb_user WHERE name LIKE ?
        //Parameters: %?%(String)
        wrapper.like("name", "?");
        List<User> users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }
}

5.4、排序

  • orderBy
    -- 排序:ORDER BY 字段, ...
    -- 例: orderBy(true, true, "id", "name") ---> order by id ASC,name ASC
  • orderByAsc
    -- 排序:ORDER BY 字段, ... ASC
    --- 例: orderByAsc("id", "name") ---> order by id ASC,name ASC
  • orderByDesc
    -- 排序:ORDER BY 字段, ... DESC
    -- 例: orderByDesc("id", "name") ---> order by id DESC,name DESC

测试?例:

package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testWrapper() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //SELECT id,user_name,password,name,age,email FROM tb_user ORDER BY age DESC
        wrapper.orderByDesc("age");
        List<User> users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }
}

5.5、逻辑查询

  • or
    -- 拼接 OR
    -- 主动调? or 表示紧接着下?个?法不是? and 连接!(不调? or 则默认为使? and 连接)
  • and
    -- AND 嵌套
    -- 例: and(i -> i.eq("name", "李?").ne("status", "活着")) ---> and (name = '李?' and status <> '活着')

测试?例:

package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testWrapper() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //SELECT id,user_name,password,name,age,email FROM tb_user WHERE name = ? OR age = ?
        wrapper.eq("name", "jack").or().eq("age", 24);
        List<User> users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }
}

5.6、select

在MP查询中,默认查询所有的字段,如果有需要也可以通过select?法进?指定字段。

package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testWrapper() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //SELECT id,name,age FROM tb_user WHERE name = ? OR age = ?
        wrapper.eq("name", "jack")
                .or()
                .eq("age", 24)
                .select("id", "name", "age");
        List<User> users = this.userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }
}

6. ActiveRecord

ActiveRecord(简称AR)?直?受动态语?( PHP 、 Ruby 等)的喜爱,? Java 作为准静态语?,对于
ActiveRecord 往往只能感叹其优雅,所以我们也在 AR 道路上进?了?定的探索,希望?家能够喜欢。

什么是ActiveRecord?
ActiveRecord也属于ORM(对象关系映射)层,由Rails最早提出,遵循标准的ORM模型:表映射到记录,
记录映射到对象,字段映射到对象属性。配合遵循的命名和配置惯例,能够很?程度的快速实现模型的操
作,?且简洁易懂。

ActiveRecord的主要思想是:

  • 每?个数据库表对应创建?个类,类的每?个对象实例对应于数据库中表的??记录;通常表的每个字
    段在类中都有相应的Field;
  • ActiveRecord同时负责把??持久化,在ActiveRecord中封装了对数据库的访问,即CURD;;
  • ActiveRecord是?种领域模型(Domain Model),封装了部分业务逻辑;

6.1、开启AR之旅

在MP中,开启AR?常简单,只需要将实体对象继承Model即可。

package com.zm.mp.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User extends Model<User> {
    private Long id;
    private String userName;
    private String password;
    private String name;
    private Integer age;
    private String email;
}

6.2、根据主键查询

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testAR() {
        User user = new User();
        user.setId(2L);
        User user2 = user.selectById();
        System.out.println(user2);
    }
}

6.3、新增数据

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testARInsert() {
        User user = new User();
        user.setName("李四");
        user.setAge(30);
        user.setEmail("lisi@qq.com");
        boolean insert = user.insert();
        System.out.println(insert);
    }
}

日志结果:

[main] [com.zm.mp.mapper.UserMapper.insert]-[DEBUG] ==> Preparing: INSERT INTO
tb_user ( name, age, email ) VALUES ( ?, ?, ?, ?, ? )
[main] [com.zm.mp.mapper.UserMapper.insert]-[DEBUG] ==> Parameters: 李四(String),
30(Integer), lisi@qq.com(String)
[main] [com.zm.mp.mapper.UserMapper.insert]-[DEBUG] <== Updates: 1

6.4、更新操作

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testAR() {
        User user = new User();
        user.setId(8L);
        user.setAge(35);
        boolean update = user.updateById();
        System.out.println(update);
    }
}

日志结果:

[main] [com.zm.mp.mapper.UserMapper.updateById]-[DEBUG] ==> Preparing: UPDATE
tb_user SET age=? WHERE id=?
[main] [com.zm.mp.mapper.UserMapper.updateById]-[DEBUG] ==> Parameters: 35(Integer),
8(Long)
[main] [com.zm.mp.mapper.UserMapper.updateById]-[DEBUG] <== Updates: 1

6.5、删除操作

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testAR() {
        User user = new User();
        user.setId(7L);
        boolean delete = user.deleteById();
        System.out.println(delete);
    }
}

6.6、根据条件查询

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testARFindById() {
        User user = new User();
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.le("age", "20");
        List<User> users = user.selectList(userQueryWrapper);
        for (User user1 : users) {
            System.out.println(user1);
        }
    }
}

7. 插件

7.1、mybatis的插件机制

MyBatis 允许你在已映射语句执?过程中的某?点进?拦截调?。默认情况下,MyBatis 允许使?插件来拦截的?
法调?包括:

  1. Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  2. ParameterHandler (getParameterObject, setParameters)
  3. ResultSetHandler (handleResultSets, handleOutputParameters)
  4. StatementHandler (prepare, parameterize, batch, update, query)

我们看到了可以拦截Executor接?的部分?法,?如update,query,commit,rollback等?法,还有其他接?
的?些?法等。

总体概括为:

  1. 拦截执?器的?法
  2. 拦截参数的处理
  3. 拦截结果集的处理
  4. 拦截Sql语法构建的处理

拦截器示例:

package com.zm.mp.plugins;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import java.util.Properties;

@Intercepts({@Signature(
        type = Executor.class,
        method = "update",
        args = {MappedStatement.class, Object.class})})
public class MyInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        //拦截?法,具体业务逻辑编写的位置
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        //创建target对象的代理对象,?的是将当前拦截器加?到该对象中
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        //属性设置
    }
}

注?到Spring容器:

/**
 * ?定义拦截器
 */
@Bean
public MyInterceptor myInterceptor(){
        return new MyInterceptor();
}

或者通过xml配置,mybatis-config.xml:

   <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <plugins>
            <plugin interceptor="com.zm.mp.plugins.MyInterceptor"></plugin>
        </plugins>
    </configuration>

7.2、执?分析插件

在MP中提供了对SQL执?的分析的插件,可?作阻断全表更新、删除的操作,注意:该插件仅适?于开发环境,
不适?于?产环境。
SpringBoot配置:

@Bean
public SqlExplainInterceptor sqlExplainInterceptor(){
        SqlExplainInterceptor sqlExplainInterceptor=new SqlExplainInterceptor();

        List<ISqlParser> sqlParserList=new ArrayList<>();

        // 攻击 SQL 阻断解析器、加?解析链
        sqlParserList.add(new BlockAttackSqlParser());
        sqlExplainInterceptor.setSqlParserList(sqlParserList);

        return sqlExplainInterceptor;
}

测试:

@Test
public void testUpdate(){
        User user=new User();
        user.setAge(20);
        int result=this.userMapper.update(user,null);
        System.out.println("result = "+result);
}

结果:

Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition
of table update operation
 at com.baomidou.mybatisplus.core.toolkit.ExceptionUtils.mpe(ExceptionUtils.java:49)
 at com.baomidou.mybatisplus.core.toolkit.Assert.isTrue(Assert.java:38)
 at com.baomidou.mybatisplus.core.toolkit.Assert.notNull(Assert.java:72)
 at
com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser.processUpdate(BlockAtta
ckSqlParser.java:45)
 at
com.baomidou.mybatisplus.core.parser.AbstractJsqlParser.processParser(AbstractJsqlParse
r.java:92)
 at
com.baomidou.mybatisplus.core.parser.AbstractJsqlParser.parser(AbstractJsqlParser.java:
67)
 at
com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler.sqlParser(Abstract
SqlParserHandler.java:76)
 at
com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor.intercept(SqlExplainIn
terceptor.java:63)
 at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
 at com.sun.proxy.$Proxy70.update(Unknown Source)
 at
org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197)
 ... 41 more

可以看到,当执?全表更新时,会抛出异常,这样有效防?了?些误操作。

7.3、性能分析插件

性能分析拦截器,?于输出每条 SQL 语句及其执?时间,可以设置最?执?时间,超过时间会抛出异常。

该插件只?于开发环境,不建议?产环境使?。

配置:
javaconfig?式

@Bean
public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor=new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100);
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
}

xml?式

 <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <plugins>
            <!-- SQL 执?性能分析,开发环境使?,线上不推荐。 maxTime 指的是 sql 最?执?时? -->
            <plugin
                    interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor">
                <property name="maxTime" value="100"/>
                <!--SQL是否格式化 默认false-->
                <property name="format" value="true"/>
            </plugin>
        </plugins>
    </configuration>

执?结果:

Time:11 ms - ID:com.zm.mp.mapper.UserMapper.selectById
Execute SQL:
 SELECT
     id,
     user_name,
     password,
     name,
     age,
     email
 FROM
    tb_user
 WHERE
    id=7

可以看到,执?时间为11ms。如果将maxTime设置为1,那么,该操作会抛出异常:

Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: The SQL
execution time is too large, please optimize !
 at com.baomidou.mybatisplus.core.toolkit.ExceptionUtils.mpe(ExceptionUtils.java:49)
 at com.baomidou.mybatisplus.core.toolkit.Assert.isTrue(Assert.java:38)
 ................

7.4、乐观锁插件

7.4.1、主要适?场景

意图:
当要更新?条记录的时候,希望这条记录没有被别?更新。

乐观锁实现?式:

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

7.4.2、插件配置

spring xml:

<bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor"/>

spring boot:

@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
 return new OptimisticLockerInterceptor();
}

7.4.3、注解实体字段

需要为实体字段添加@Version注解。
第?步,为表添加version字段,并且设置初始值为1:

ALTER TABLE `tb_user`
ADD COLUMN `version` int(10) NULL AFTER `email`;

UPDATE `tb_user` SET `version`='1';

第?步,为User实体对象添加version字段,并且添加@Version注解:

@Version
private Integer version;

7.4.4、测试

测试?例:

@Test
public void testUpdate(){
   User user = new User();
   user.setAge(30);
   user.setId(2L);
   user.setVersion(1); //获取到version为1

   int result = this.userMapper.updateById(user);
   System.out.println("result = " + result);
}

执??志:

main] [com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser]-[DEBUG]
Original SQL: UPDATE tb_user SET age=?,
version=? WHERE id=? AND version=?
[main] [com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser]-[DEBUG] parser
sql: UPDATE tb_user SET age = ?, version = ? WHERE id = ? AND version = ?
[main] [org.springframework.jdbc.datasource.DataSourceUtils]-[DEBUG] Fetching JDBC
Connection from DataSource
[main] [org.mybatis.spring.transaction.SpringManagedTransaction]-[DEBUG] JDBC
Connection [HikariProxyConnection@540206885 wrapping
com.mysql.jdbc.JDBC4Connection@27e0f2f5] will not be managed by Spring
[main] [com.zm.mp.mapper.UserMapper.updateById]-[DEBUG] ==> Preparing: UPDATE
tb_user SET age=?, version=? WHERE id=? AND version=?
[main] [com.zm.mp.mapper.UserMapper.updateById]-[DEBUG] ==> Parameters: 30(Integer),
2(Integer), 2(Long), 1(Integer)
[main] [com.zm.mp.mapper.UserMapper.updateById]-[DEBUG] <== Updates: 1
[main] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Closing non transactional
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@30135202]
result = 1

可以看到,更新的条件中有version条件,并且更新的version为2。
如果再次执?,更新则不成功。这样就避免了多?同时更新时导致数据的不?致。

7.4.5、特别说明

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

8. Sql 注?器

我们已经知道,在MP中,通过AbstractSqlInjector将BaseMapper中的?法注?到了Mybatis容器,这样这些?法
才可以正常执?。
那么,如果我们需要扩充BaseMapper中的?法,?该如何实现呢?
下?我们以扩展findAll?法为例进?学习。

8.1、编写MyBaseMapper

package com.zm.mp.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;

public interface MyBaseMapper<T> extends BaseMapper<T> {
 List<T> findAll();
}

其他的Mapper都可以继承该Mapper,这样实现了统?的扩展。
如:

package com.zm.mp.mapper;
import com.zm.mp.pojo.User;

public interface UserMapper extends MyBaseMapper<User> {
 User findById(Long id);
}

8.2、编写MySqlInjector

如果直接继承AbstractSqlInjector的话,原有的BaseMapper中的?法将失效,所以我们选择继承
DefaultSqlInjector进?扩展。

package com.zm.mp.sqlInjector;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import java.util.List;

public class MySqlInjector extends DefaultSqlInjector {
    @Override
    public List<AbstractMethod> getMethodList() {
        List<AbstractMethod> methodList = super.getMethodList();
        methodList.add(new FindAll());

        // 再扩充?定义的?法
        list.add(new FindAll());
        return methodList;
    }
}

8.3、编写FindAll

package com.zm.mp.sqlInjector;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;

public class FindAll extends AbstractMethod {
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sqlMethod = "findAll";
        String sql = "select * from " + tableInfo.getTableName();
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addSelectMappedStatement(mapperClass, sqlMethod, sqlSource, modelClass, tableInfo);
    }
}

8.4、注册到Spring容器

/**
* ?定义SQL注?器
*/
@Bean
public MySqlInjector mySqlInjector(){
 return new MySqlInjector();
}

8.5、测试

@Test
public void testFindAll(){
   List<User> users = this.userMapper.findAll();
   for (User user : users) {
      System.out.println(user);
   }
}

输出的SQL:

[main] [com.zm.mp.mapper.UserMapper.findAll]-[DEBUG] ==> Preparing: select * from
tb_user
[main] [com.zm.mp.mapper.UserMapper.findAll]-[DEBUG] ==> Parameters:
[main] [com.zm.mp.mapper.UserMapper.findAll]-[DEBUG] <== Total: 10

?此,我们实现了全局扩展SQL注?器。


9. ?动填充功能

有些时候我们可能会有这样的需求,插?或者更新数据时,希望有些字段可以?动填充数据,?如密码、version等。在MP中提供了这样的功能,可以实现?动填充。

9.1、添加@TableField注解

@TableField(fill = FieldFill.INSERT) //插?数据时进?填充
private String version;

为email添加?动填充功能,在新增数据时有效。
FieldFill提供了多种模式选择:

public enum FieldFill {
    /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插?时填充字段
     */
    INSERT,
    /**
     * 更新时填充字段
     */
    UPDATE,
    /**
     * 插?和更新时填充字段
     */
    INSERT_UPDATE
}

9.2、编写MyMetaObjectHandler

package com.zm.mp.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        Object password = getFieldValByName("version", metaObject);
        if (null == password) {
            //字段为空,可以进?填充
            setFieldValByName("version", "123456", metaObject);
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {
    }
}

9.3、测试

@Test
public void testInsert(){
        User user=new User();
        user.setName("冰冰");
        user.setAge(30);
        user.setVersion(1);
        int result=this.userMapper.insert(user);
        System.out.println("result = "+result);
}

10. 逻辑删除

开发系统时,有时候在实现功能时,删除操作需要实现逻辑删除,所谓逻辑删除就是将数据标记为删除,?并?真正的物理删除(?DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的?的就是避免数据被真正的删除。
MP就提供了这样的功能,?便我们使?,接下来我们?起学习下。

10.1、修改表结构

为tb_user表增加deleted字段,?于表示数据是否被删除,1代表删除,0代表未删除。

ALTER TABLE `tb_user`
ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '1代表删除,0代表未删除' AFTER `version`;

同时,也修改User实体,增加deleted属性并且添加@TableLogic注解:

@TableLogic
private Integer deleted;

10.2、配置

application.properties:

# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0

10.3、测试

@Test
public void testDeleteById(){
 this.userMapper.deleteById(2L);
}

执?的SQL:

[main] [com.zm.mp.mapper.UserMapper.deleteById]-[DEBUG] ==> Preparing: UPDATE
tb_user SET deleted=1 WHERE id=? AND deleted=0
[main] [com.zm.mp.mapper.UserMapper.deleteById]-[DEBUG] ==> Parameters: 2(Long)
[main] [com.zm.mp.mapper.UserMapper.deleteById]-[DEBUG] <== Updates: 1

测试查询:

@Test
public void testSelectById(){
 User user = this.userMapper.selectById(2L);
 System.out.println(user);
}

执?的SQL:

[main] [com.zm.mp.mapper.UserMapper.selectById]-[DEBUG] ==> Preparing: SELECT
id,user_name,password,name,age,email,version,deleted FROM tb_user WHERE id=? AND
deleted=0
[main] [com.zm.mp.mapper.UserMapper.selectById]-[DEBUG] ==> Parameters: 2(Long)
[main] [com.zm.mp.mapper.UserMapper.selectById]-[DEBUG] <== Total: 0

至此,已经实现了逻辑删除。


11. 代码?成器

AutoGenerator 是 MyBatis-Plus 的代码?成器,通过 AutoGenerator 可以快速?成 Entity、Mapper、MapperXML、Service、Controller 等各个模块的代码,极?的提升了开发效率。

11.1、创建?程

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.4.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>

        <groupId>com.zm</groupId>
        <artifactId>zm-mp-generator</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>zm-mp-generator</name>
        <description>Demo project for Spring Boot</description>
        <properties>
            <java.version>11</java.version>
        </properties>

        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
            <!--mybatis-plus的springboot?持-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.1.1</version>
            </dependency>
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-generator</artifactId>
                <version>3.1.1</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-freemarker</artifactId>
            </dependency>
            <!--mysql驱动-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--简化代码的?具包-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>

11.2、代码

package com.zm.mp.generator;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

/**
 * <p>
 * mysql 代码?成器演示例?
 * </p>
 */
public class MysqlGenerator {
    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输?" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输?正确的" + tip + "!");
    }

    /**
     * RUN THIS
     */
    public static void main(String[] args) {
        // 代码?成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("zm");
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mp? useUnicode = true & useSSL = false & characterEncoding = utf8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("模块名"));
        pc.setParent("com.zm.mp.generator");
        mpg.setPackageInfo(pc);

        // ?定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // ?定义输??件名称
                return projectPath + "/zm-mp-generator/src/main/resources/mapper/" +
                        pc.getModuleName() + "/" + tableInfo.getEntityName() + "Mapper" +
                        StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        mpg.setTemplate(new TemplateConfig().setXml(null));
        
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);

        //strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEnt ity");
        strategy.setEntityLombokModel(true);

        //strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
        strategy.setInclude(scanner("表名"));
        strategy.setSuperEntityColumns("id");
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        
        // 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
}

通过测试发现,代码已经生成。


12. MybatisX 快速开发插件

MybatisX 是?款基于 IDEA 的快速开发插件,为效率??。
安装?法:打开 IDEA,进? File -> Settings -> Plugins -> Browse Repositories,输? mybatisx 搜索并安装。
功能:

  • Java 与 XML 调回跳转
  • Mapper ?法?动?成 XML

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:07:52  更:2022-07-17 16:08:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 15:40:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码