美文网首页JavaMySQLmybatis-plus
MyBatis-Plus 学习笔记

MyBatis-Plus 学习笔记

作者: 青丶空 | 来源:发表于2020-06-25 22:01 被阅读0次

    MyBatis Plus

    本文档基于 MyBatis-Plus 官方文档编写,详情请参见 MyBatis-Plus 官网

    MyBatis Plus 概述

    MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上增强了功能而不做改变,为了简化开发、开发效率而生。

    特性

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

    支持数据库

    • mysql 、 mariadb 、 oracle 、 db2 、 h2 、 hsql 、 sqlite 、 postgresql 、 sqlserver
    • 达梦数据库 、 虚谷数据库 、 人大金仓数据库

    入门程序

    基本步骤

    1、创建项目

    2、导入依赖

    3、编写相应配置文件

    4、使用

    数据库语句

    数据库语句

    CREATE DATABASE mybatisplus;
    
    USE mybatisplus;
    
    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)
    );
    

    数据库 Data 脚本

    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');
    

    使用 Spring 步骤

    使用 Spring 步骤

    1、创建 Maven 项目

    2、 引入相应的依赖

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.0.2.RELEASE</spring.version>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <mysql.version>8.0.16</mysql.version>
        <mybatis.version>3.4.5</mybatis.version>
    </properties>
    
    <dependencies>
        
        <!-- spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- log start -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- log end -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>compile</scope>
        </dependency>
    
    </dependencies>
    

    3、编写配置文件 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"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           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
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd">
        <!-- 扫描的位置 -->
        <context:component-scan base-package="com.mybatis.study" />
        <!-- 导入 JDBC 配置文件 -->
        <context:property-placeholder location="jdbc.properties" />
        <!-- 配置连接池 -->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="driverClassName" value="${jdbc.driverClass}" />
            <property name="url" value="${jdbc.url}" />
            <property name="username" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
        </bean>
        <!-- 配置 MyBatis-Plus 类 -->
        <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource" />
        </bean>
        <!-- 扫描 Mapper 所在的包 -->
        <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.mybatis.study.mapper" />
        </bean>
        <!-- 配置事务 -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource" />
        </bean>
        <tx:annotation-driven transaction-manager="transactionManager" />
    </beans>
    
    

    4、编写 pojo 类和 mapper 接口

    pojo 类

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @TableName("user")
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    
    }
    

    mapper 接口

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

    5、 测试运行

    测试类

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:applicationContext.xml"})
    public class UserTest {
        @Autowired
        private UserMapper userMapper;
        @Test
        public void test01(){
            List<User> users = userMapper.selectList(null);
            users.forEach(System.out::println);
        }
    }
    

    测试结果

    1587958492400.png

    使用 Spring Boot 步骤

    使用 Spring Boot 步骤

    1、创建 Spring Boot 项目

    2、添加依赖

    <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.6.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.1</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>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
    

    3、编写配置文件 application.yml

    # DataSource Config
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mybatisplus
        username: root
        password: 123
    

    4、在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 mapper 文件夹

    @MapperScan("com.mybatis.study.mapper")
    @SpringBootApplication
    public class MybatisPlusStudyApplication {
        public static void main(String[] args) {
            SpringApplication.run(MybatisPlusStudyApplication.class, args);
        }
    }
    

    5、编写 pojo 类和 mapper 接口

    pojo 类

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

    mapper 接口

    public interface UserMapper extends BaseMapper<User> {}
    

    6、运行测试

    测试类

    @SpringBootTest
    class MybatisPlusStudyApplicationTests {
        @Autowired
        private UserMapper userMapper;
        @Test
        void contextLoads() {
            List<User> users = userMapper.selectList(null);
            users.forEach(System.out::println);
        }
    }
    

    运行结果

    配置 Spring 日志

    导入 Log4J 日志的坐标

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>${log4j.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    

    编写 log4j 的配置文件

    log4j.rootLogger=DEBUG,Console
    
    #Console  
    log4j.appender.Console=org.apache.log4j.ConsoleAppender  
    log4j.appender.console.Target=System.out
    log4j.appender.Console.layout=org.apache.log4j.PatternLayout  
    log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n  
    
    log4j.logger.org.apache=ERROR
    log4j.logger.org.mybatis=ERROR
    log4j.logger.org.springframework=ERROR
    #这个需要
    log4j.logger.log4jdbc.debug=ERROR
    log4j.logger.com.gk.mapper=ERROR
    
    log4j.logger.jdbc.audit=ERROR
    log4j.logger.jdbc.resultset=ERROR
    #这个打印SQL语句非常重要
    log4j.logger.jdbc.sqlonly=DEBUG
    log4j.logger.jdbc.sqltiming=ERROR
    log4j.logger.jdbc.connection=FATAL
    

    配置 Spring Boot 日志

    在 Spring Boot 中配置日志(编写配置文件 application.yml

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

    运行程序

    MyBatis-Plus 常用注解

    @TableName

    • 描述:表名注解
    属性 类型 必须指定 默认值 描述
    value String "" 表名
    schema String "" schema
    keepGlobalPrefix boolean false 是否保持使用全局的 tablePrefix 的值(如果设置了全局 tablePrefix 且自行设置了 value 的值)
    resultMap String "" xml 中 resultMap 的 id
    autoResultMap boolean false 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建并注入)

    @TableId

    • 描述:主键注解
    属性 类型 必须指定 默认值 描述
    value String "" 主键字段名
    type Enum IdType.NONE 主键类型

    IdType

    描述
    AUTO 数据库ID自增
    NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
    INPUT insert前自行set主键值
    ASSIGN_ID 分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
    ASSIGN_UUID 分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认default方法)
    ID_WORKER 分布式全局唯一ID 长整型类型(please use ASSIGN_ID)
    UUID 32位UUID字符串(please use ASSIGN_UUID)
    ID_WORKER_STR 分布式全局唯一ID 字符串类型(please use ASSIGN_ID)

    @TableField

    • 描述:字段注解(非主键)
    属性 类型 必须指定 默认值 描述
    value String "" 字段名
    el String "" 映射为原生 #{ ... } 逻辑,相当于写在 xml 里的 #{ ... } 部分
    exist boolean true 是否为数据库表字段
    condition String "" 字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考
    update String "" 字段 update set 部分注入, 例如:update="%s+1":表示更新时会set version=version+1(该属性优先级高于 el 属性)
    insertStrategy Enum N DEFAULT 举例:NOT_NULL: insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
    updateStrategy Enum N DEFAULT 举例:IGNORED: update table_a set column=#{columnProperty}
    whereStrategy Enum N DEFAULT 举例:NOT_EMPTY: where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
    fill Enum FieldFill.DEFAULT 字段自动填充策略
    select boolean true 是否进行 select 查询
    keepGlobalFormat boolean false 是否保持使用全局的 format 进行处理
    jdbcType JdbcType JdbcType.UNDEFINED JDBC类型 (该默认值不代表会按照该值生效)
    typeHandler Class<? extends TypeHandler> UnknownTypeHandler.class 类型处理器 (该默认值不代表会按照该值生效)
    numericScale String "" 指定小数点后保留的位数

    FieldStrategy

    描述
    IGNORED 忽略判断
    NOT_NULL 非NULL判断
    NOT_EMPTY 非空判断(只对字符串类型字段,其他类型字段依然为非NULL判断)
    DEFAULT 追随全局配置

    FieldFill

    描述
    DEFAULT 默认不处理
    INSERT 插入时填充字段
    UPDATE 更新时填充字段
    INSERT_UPDATE 插入和更新时填充字段

    @Version

    • 描述:乐观锁注解、标记 @Verison 在字段上

    @EnumValue

    • 描述:通枚举类注解(注解在枚举字段上)

    @TableLogic

    • 描述:表字段逻辑处理注解(逻辑删除)
    属性 类型 必须指定 默认值 描述
    value String "" 逻辑未删除值
    delval String "" 逻辑删除值

    @SqlParser

    • 描述:租户注解,支持method上以及mapper接口上
    属性 类型 必须指定 默认值 描述
    filter boolean false true: 表示过滤SQL解析,即不会进入ISqlParser解析链,否则会进解析链并追加例如tenant_id等条件

    @KeySequence

    • 描述:序列主键策略 oracle
    • 属性:value、resultMap
    属性 类型 必须指定 默认值 描述
    value String "" 序列名
    clazz Class Long.class id的类型, 可以指定String.class,这样返回的Sequence值是字符串"1"

    常见 CRUD 操作及扩展

    Spring Boot 基本操作

    前期准备步骤参见[使用 Spring Boot 步骤](#使用 Spring Boot 步骤)

    插入操作

    简单的插入操作

    @Test
    void insertTest(){
        User user = new User();
        user.setName("Mybatis");
        user.setAge(11);
        user.setEmail("123456@qq.com");
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }
    

    运行结果

    由于我们在插入操作时并没有指定 user 表的主键,但是查询数据库后发现 MyBatis-Plus 帮我们自动生成了主键。这是 MyBatis-Plus 的主键生成策略!

    主键生成策略

    默认 ID_WORKER 全局唯一 ID,在 MyBatis-Plus 3.3.0 版本后被 ASSIGN_ID 代替,详情见 MyBatis-Plus 常用注解-IdType

    雪花算法
    snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096 个ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一!

    配置主键自增策略

    1. 在实体类的主键上加上 @TableId(type =IdType.AUTO)

    2. 将数据库中的主键字段设置为自增长

      ALTER TABLE USER CHANGE id id BIGINT AUTO_INCREMENT 
      
    1. 测试插入

    其余字段详情见 MyBatis-Plus 常用注解-IdType

    更新操作

    简单的更新操作

    @Test
    void updateTest() {
        User user = User.builder()
            .id(5L)
            .name("Updated")
            .age(99)
            .build();
        userMapper.updateById(user);
    }
    
    自动填充

    阿里开发手册:所有的数据库表基本都需要配置上:gmt_create(create_time)、gmt_update(update_time) 并且实现自动化

    在工作中不允许我们修改数据库,此处仅为演示

    方式一:使用数据库级别完成

    1. 在数据表中新增字段 create_timeupdate_time
    ALTER TABLE USER 
    ADD create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间';
    ALTER TABLE USER ADD update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间';
    
    1. 在实体类中新增属性

      private Date createTime;
      private Date updateTime;
      
    2. 执行更新操作

      @Test
      void updateTest() {
          User user = User.builder()
              .id(4L)
              .name("UpdatedTime")
              .age(55)
              .build();
          userMapper.updateById(user);
      }
      
    1. 更新查看结果

      更新前

    更新后

    方式二:使用代码完成

    1. 将数据表的默认值和更新操作删除

      ALTER TABLE USER
        CHANGE create_time create_time DATETIME NULL COMMENT '创建时间',
        CHANGE update_time update_time DATETIME NULL COMMENT '修改时间';
      
    2. 在实体类上增加注解

      @TableField(fill = FieldFill.INSERT)
      private Date createTime;
      @TableField(fill = FieldFill.INSERT_UPDATE)
      private Date updateTime;
      
    3. 编写处理器处理注解

      @Slf4j
      @Component
      public class MyDateObjectHandler implements MetaObjectHandler {
          /**
           * 插入时的策略
           * @param metaObject 源数据对象
           */
          @Override
          public void insertFill(MetaObject metaObject) {
              log.info("start insert fill......");
              this.setFieldValByName("createTime",new Date(),metaObject);
              this.setFieldValByName("updateTime",new Date(),metaObject);
          }
      
          /**
           * 更新时的策略
           * @param metaObject 源数据对象
           */
          @Override
          public void updateFill(MetaObject metaObject) {
              log.info("start update fill......");
              this.setFieldValByName("updateTime",new Date(),metaObject);
          }
      }
      
    1. 执行更新操作
    乐观锁

    乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论做什么都不上锁!如果出现了问题,再次更新值测试。

    悲观锁:顾名思义十分悲观,它总是认为会出现问题,无论做什么都上锁!再去进行操作。

    乐观锁实现方式:

    • 取出记录时,获取当前的 version
    • 更新时,带上这个 version
    • 执行更新时, update xxx set version = newVersion where version = oldVersion
    • 如果 version 不正确,则更新失败
    乐观锁:1、先查询,获得版本号 version = 1
    -- A
    update user set name = "kuangshen", version = version + 1
    where id = 2 and version = 1
    -- B 线程抢先完成,这个时候version = 2,会导致A 修改失败!
    update user set name = "kuangshen", version = version + 1
    where id = 2 and version = 1
    

    乐观锁的使用

    1. 在数据库中新增 version 字段

      ALTER TABLE USER ADD VERSION INT DEFAULT 1 COMMENT '版本号';
      
    1. 在实体类中增加 version 字段

      @Version
      private Integer version;
      
    2. 注册组件

      @MapperScan("com.hsh.study.mapper")
      @EnableTransactionManagement
      @Configuration
      public class MyBatisPlusConfig {
          /**
           * 注册乐观锁插件
           * @return 实例
           */
          @Bean
          public OptimisticLockerInterceptor optimisticLockerInterceptor(){
              return new OptimisticLockerInterceptor();
          }
      }
      
    1. 进行测试

      测试方法

      @Test
      void optimisticLockerTest() {
          User user = userMapper.selectById(1L);
          user.setName("lockedTest");
          user.setEmail("110@test.com");
          userMapper.updateById(user);
      }
      

      测试结果

    删除操作

    删除操作常见的三种方式

    /**
     * 根据 id 删除
     */
    @Test
    void deleteTest(){
        userMapper.deleteById(1255372915881406466L);
    }
    /**
     * 通过 Id 集合进行删除
     */
    @Test
    void deleteIdsTest(){
        userMapper.deleteBatchIds(Arrays.asList(1255373036727685122L,1255373036727685123L));
    }
    /**
     * 通过 Map 来删除
     */
    @Test
    void deleteMapTest(){
        Map<String, Object> map = new HashMap<>();
        map.put("name","张三");
        userMapper.deleteByMap(map);
    }
    
    逻辑删除

    逻辑删除:通过一个标记表示此条数据已被删除,不会再数据库中直接删除数据!deleted = 0 -> deleted = 1

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

    1、修改数据库,添加 deleted 字段

    alter table `user` add deleted int default 0 comment '逻辑删除';
    

    2、在实体类中添加 deleted 字段

    1. 在配置文件 application.yml 中加入配置

      # 配置 MyBatis-Plus
      mybatis-plus:
        configuration:
          # 配置日志
          log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
        # 配置逻辑删除
        global-config:
          db-config:
            logic-delete-value: 1
            logic-not-delete-value: 0
      
    2. 在实体类上添加 @TableLogic 注解

      @TableLogic
      private Integer deleted;
      

    4、测试删除

    查看数据库

    查询操作

    常见的查询操作

    @Test
    void test1(){
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
    @Test
    void test2(){
        User user = userMapper.selectById(3L);
        System.out.println(user);
    }
    @Test
    void test3(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 1255379859656523778L));
        // 查询不到 1255379859656523778L 是因为之前被逻辑删除了!
        users.forEach(System.out::println);
    }
    @Test
    void test4(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("email","123456@qq.com");
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }
    
    分页查询

    MyBatis-Plus 中内置了分页插件

    1、配置分页插件

    /**
     * 分页插件
     * @return 实例
     */
    @Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }
    

    2、使用

    @Test
    void pageLimitTest(){
        /* new Page(current,size)
         * current:当前页
         * size:每页大小
         */
        Page<User> page = new Page<>(1,5);
        // 执行分页查询 自动回写到 page 对象中
        userMapper.selectPage(page, null);
        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal());
    }
    

    Spring 基本操作

    前期准备步骤参见[使用 Spring 步骤](#使用 Spring 步骤)

    插入操作

    简单的插入操作

    @Test
    public void insertTest(){
        User user = User.builder()
            .name("hhh")
            .age(112)
            .email("123@11.11")
            .build();
        userMapper.insert(user);
    }
    

    运行结果

    更新操作

    简单的更新操作

    @Test
    void updateTest() {
        User user = User.builder()
            .id(1257194050558160897L)
            .name("1122")
            .age(36)
            .build();
        userMapper.updateById(user);
    }
    
    自动填充策略

    阿里开发手册:所有的数据库表基本都需要配置上:gmt_create(create_time)、gmt_update(update_time) 并且实现自动化

    方式一:使用数据库级别完成 参考 Spring Boot 中的自动填充,此处不做演示

    方式二:使用代码完成

    1. 将数据表的默认值和更新操作删除

      ALTER TABLE USER
        CHANGE create_time create_time DATETIME NULL COMMENT '创建时间',
        CHANGE update_time update_time DATETIME NULL COMMENT '修改时间';
      
    2. 在实体类上增加注解

      @TableField(fill = FieldFill.INSERT)
      private Date createTime;
      @TableField(fill = FieldFill.INSERT_UPDATE)
      private Date updateTime;
      
    3. 编写处理器处理注解

      @Slf4j
      @Component
      public class MyDateObjectHandler implements MetaObjectHandler {
          /**
           * 插入时的策略
           * @param metaObject 源数据对象
           */
          @Override
          public void insertFill(MetaObject metaObject) {
              log.info("start insert fill......");
              this.setFieldValByName("createTime",new Date(),metaObject);
              this.setFieldValByName("updateTime",new Date(),metaObject);
          }
      
          /**
           * 更新时的策略
           * @param metaObject 源数据对象
           */
          @Override
          public void updateFill(MetaObject metaObject) {
              log.info("start update fill......");
              this.setFieldValByName("updateTime",new Date(),metaObject);
          }
      }
      
    4. 编写 applicationContext.xml 配置文件

      <!-- 配置 MyBatis-Plus 的全局配置 -->
      <bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
          <property name="metaObjectHandler">
              <!-- 编写自己的 MyMetaObjectHandler -->
              <bean class="com.mybatis.study.handler.MyMetaObjectHandler" />
          </property>
      </bean>
      <!-- 配置 MyBatis-Plus 类 -->
      <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
          <property name="dataSource" ref="dataSource" />
          <property name="globalConfig" ref="globalConfig" />
      </bean>
      
    1. 执行更新操作
    乐观锁

    乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论做什么都不上锁!如果出现了问题,再次更新值测试。

    悲观锁:顾名思义十分悲观,它总是认为会出现问题,无论做什么都上锁!再去进行操作。

    乐观锁实现方式:

    • 取出记录时,获取当前的 version
    • 更新时,带上这个 version
    • 执行更新时, update xxx set version = newVersion where version = oldVersion
    • 如果 version 不正确,则更新失败

    乐观锁的使用

    1. 在数据库中新增 version 字段

      ALTER TABLE USER ADD VERSION INT DEFAULT 1 COMMENT '版本号';
      
    2. 在实体类中增加 version 字段

      @Version
      private Integer version;
      
    3. 注册组件,配置 applicationContext.xml 配置文件

      <!-- 配置 MyBatis-Plus 类 -->
      <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
          <!-- 配置数据源 -->
          <property name="dataSource" ref="dataSource" />
          <!-- 配置全局配置 -->
          <property name="globalConfig" ref="globalConfig" />
          <!-- 配置插件 -->
          <property name="plugins">
              <list>
                  <!-- 注册乐观锁插件 -->
                  <bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor" />
              </list>
          </property>
      </bean>
      
    4. 进行测试

      测试方法

      @Test
      public void optimisticLockerTest() {
          User user = userMapper.selectById(1257194050558160897L);
          user.setName("lockedTest");
          user.setEmail("120@test.com");
          userMapper.updateById(user);
      }
      

      测试结果

    删除操作

    删除操作常见的三种方式

    /**
     * 根据 id 删除
     */
    @Test
    void deleteTest(){
        userMapper.deleteById(1255372915881406466L);
    }
    /**
     * 通过 Id 集合进行删除
     */
    @Test
    void deleteIdsTest(){
        userMapper.deleteBatchIds(Arrays.asList(1255373036727685122L,1255373036727685123L));
    }
    /**
     * 通过 Map 来删除
     */
    @Test
    void deleteMapTest(){
        Map<String, Object> map = new HashMap<>();
        map.put("name","张三");
        userMapper.deleteByMap(map);
    }
    
    逻辑删除

    逻辑删除:通过一个标记表示此条数据已被删除,不会再数据库中直接删除数据!deleted = 0 -> deleted = 1

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

    1、修改数据库,添加 deleted 字段

    alter table `user` add deleted int default 0 comment '逻辑删除';
    

    2、在实体类中添加 deleted 字段

    1. 在配置文件 applicationContext.xml 中加入配置

      <!-- Mybatis-Plus 全局配置 -->
      <bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig">
          <!-- 自动填充 -->
          <property name="metaObjectHandler">
          <!-- 编写自己的 MyMetaObjectHandler -->
               <bean class="com.mybatis.study.handler.MyMetaObjectHandler" />
          </property>
          <!-- 逻辑删除 -->
          <property name="dbConfig" >
              <bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig">
                  <property name="logicDeleteValue" value="1" />
                  <property name="logicNotDeleteValue" value="0" />
              </bean>
          </property>
      </bean>
      <!-- 配置 MyBatis-Plus 类 -->
      <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
          <property name="dataSource" ref="dataSource" />
          <property name="globalConfig" ref="globalConfig" />
      </bean>
      
    2. 在实体类上添加 @TableLogic 注解

      @TableLogic
      private Integer deleted;
      

    4、测试删除

    查看数据库

    查询操作

    常见的查询操作

    @Test
    void test1(){
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
    @Test
    void test2(){
        User user = userMapper.selectById(3L);
        System.out.println(user);
    }
    @Test
    void test3(){
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 1255379859656523778L));
        // 查询不到 1255379859656523778L 是因为之前被逻辑删除了!
        users.forEach(System.out::println);
    }
    @Test
    void test4(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("email","123456@qq.com");
        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }
    
    分页查询

    MyBatis-Plus 中内置了分页插件

    1、配置分页插件

    <!-- 配置 MyBatis-Plus 类 -->
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="globalConfig" ref="globalConfig" />
        <property name="plugins">
            <list>
                <!-- 配置分页插件 -->
                <bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor" />
            </list>
        </property>
    </bean>
    

    2、使用

    @Test
    void pageLimitTest(){
        /* new Page(current,size)
         * current:当前页
         * size:每页大小
         */
        Page<User> page = new Page<>(1,5);
        // 执行分页查询 自动回写到 page 对象中
        userMapper.selectPage(page, null);
        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal());
    }
    

    扩展: Wrapper 的使用

    当我们需要写一些复杂 SQL 语句时,可以使用 Wrapper 代替,所用 Wrapper 参数解释参见 条件构造器

    下面列举常用 Wrapper 及其使用结果

    allEq

    allEq -> 全部相等或个别 isNull

    @Test
    void allEqTest(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        Map<String, Object> map = new HashMap<>();
        map.put("name","张三");
        map.put("age",null);
        wrapper.allEq(map);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
    

    eq

    eq -> 相等(用于判断一个条件时)

    @Test
    void eqTest(){
        wrapper.eq("email","123456@qq.com");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
    

    inSql

    有两种不同的用法:

    ​ 1. inSql("age","1,2,3,4,5") -> age IN (1,2,3,4,5)

    ​ 2. inSql("id","select id from user where id < 5") -> id IN (SELECT id FROM user WHERE id < 5)

    @Test
    void inSqlTest1(){
        wrapper.inSql("age","10,11,20");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
    
    @Test
    void inSqlTest2(){
        wrapper.inSql("id","select id from user where id < 10");
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
    

    其余常见方法参见如下映射表

    方法名 数据库名 作用
    ne <> 不等于
    gt > 大于
    ge >= 大于等于
    lt < 小于
    le <= 小于等于
    between BETWEEN 值1 AND 值2 在值 1 和值 2 之间
    notBetween NOT BETWEEN 值1 AND 值2 不在值 1 和值 2 之间
    like / notLike LIKE '%值%' / NOT LIKE '值' 模糊搜索
    likeLeft / likeRight LIKE '%值' / LIKE '值%' 左右模糊匹配
    isNull / isNotNull IS NULL / IS NOT NULL 是否为空
    in / notIn IN (值1,2...) / NOT IN (值1,2...) 是否在集合中
    inSql / notInSql 见例子 子查询或查询集合
    groupBy GROUP BY 字段 根据字段分组
    orderByAsc / orderByDesc ORDER BY 字段 ASC / ORDER BY 字段 DESC 升序排序 / 降序排序
    其余详细字段参见官方文档 官方文档 其余详细字段参见官方文档

    相关文章

      网友评论

        本文标题:MyBatis-Plus 学习笔记

        本文链接:https://www.haomeiwen.com/subject/kesefktx.html