Mybatis-plus工具学习笔记(2)---[常用注解,条件构造器,插件使用]

近期也是计划学习mybatis-plus,扩展知识;
推荐官方文档食用学习–>https://baomidou.com/
Mybatis-plus官方文档

本次学习根据B站尚硅谷教学视频:【尚硅谷】2022版MyBatisPlus教程(一套玩转mybatis-plus)


1.常用注解


1.1 @TableName


在之前学习的时候,注意到并没有指定操作哪个数据表,但是操作时它就会找到用户user数据表;这是根据实体类User来判定找到的;

那么此时将数据库中的用户表名修改后,注意观察效果; 将user 表名改为 t_user

在这里插入图片描述

找到之前编写的测试类MybatisPlusTest
运行测试方法;

在这里插入图片描述
此时发现程序报错数据表user不存在;因为默认识别的是查询数据表user,但是将数据表user改名为t_user了,也就无法匹配.
在这里插入图片描述

那么如何自动识别到要查询的数据表t_user呢?

两种方式:

  • 首先,可以选择在实体类User处使用注解@TableName来标注数据表的名称
    在这里插入图片描述
    再运行测试方法试试,可成功操作对应的数据表t_user
    在这里插入图片描述

全局配置

  • 当然,也可以选择第二种做法,在配置文件application.yml中进行配置数据表的识别;

先将刚才在实体类User写的注解@TableName("t_user")注释掉;

application.yml中配置mybatis的全局配置;对于项目使用的数据表公共前缀进行标注;

# 设置数据源类型,数据库信息;
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_study_xiaozhi?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
#加入日志功能;
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  #可配置mybatis的全局配置
  global-config:
    db-config:
      table-prefix: t_

同样测试一下,也可以正常使用


1.2 @TableId


通过前面的学习,了解到mybatis-plus是默认将数据表中的id作为主键的,要是将数据表的字段id改为uid呢?是否还能正确识别到主键?

将数据表中的id修改为uid

在这里插入图片描述

当然,实体类User的属性id也修改为uid

在这里插入图片描述

MybatisPlusTest中执行测试的添加功能;

//测试新增功能;
@Test
public void startAdd() {
    User user = new User();
    user.setName("小智");
    user.setAge(22);
    user.setEmail("xiaozhi@ceshi.com");
    //新增数据;
    //INSERT INTO user ( Uid, name, age, email ) VALUES ( ?, ?, ?, ? )
    int insert = userMapper.insert(user);
    //是否添加成功;
    System.out.println("新增了" + insert + "条数据----------");
    //立即获取到添加数据的主键Id;
    System.out.println("立即获取新增的用户主键:" + user.getUid());
}

运行之,显而易见出现了sql错误.提示uid这个字段没有设定的默认值,即无法识别它的主键身份.
在这里插入图片描述
那么解决处理,可使用注解@TableId来进行标注.
打开实体类User;在属性uid上使用注解;即可将属性uid对应的字段uid标识为主键;

@Data
@NoArgsConstructor
@AllArgsConstructor
//标注数据表名;
//@TableName("t_user")
public class User {
    @TableId
    private Long uid;

    private String name;

    private Integer age;

    private String email;
}

测试执行刚才的添加方法,数据成功存入;
在这里插入图片描述


键入注解TableId,可看到value和type方法;这两个方法可操作的.
在这里插入图片描述

模拟场景,此时要是将用户User的属性uid改为id. 而数据表的字段仍然是uid,那么属性该如何识别到对应的字段uid呢?

可使用value属性进行标注即可;
在这里插入图片描述


再看看type的功能; 可操作属性的策略;
先将数据表中的uid字段设置为自增;
在这里插入图片描述

首先测试一下添加数据方法;
在这里插入图片描述

运行之,发现uid还是默认的雪花算法生成的,并不是自增的;
在这里插入图片描述
在这里插入图片描述

那么实际上就需要用注解@TableId的属性type进行标注自增属性;
可以看注解@TableId源码中的type()方法返回值类型IdType的源码,这是个枚举类,ok很容易找到这样一个方法来标注自增.
在这里插入图片描述

在实体类User设置即可;

@Data
@NoArgsConstructor
@AllArgsConstructor
//标注数据表名;
//@TableName("t_user")
public class User {
    //将属性对应的字段标注为主键;
    //value属性可标注对应的字段;

    @TableId(value = "uid",type = IdType.AUTO )
    private Long id;

    private String name;

    private Integer age;

    private String email;
}

测试执行添加数据的方法;OK,确实有自增效果了;
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


常见的主键设定策略:

  • 默认的:IdType.ASSIGN_ID 基于雪花算法的策略生成数据id,与数据库id是否设置自增无关
  • IdType.AUTO 使用数据库的自增策略,该类型请确保数据库设置了id自增,否则无效.

全局配置

当然,不使用注解也是可以的,在application.yml中进行全局配置即可.使用参数id-type配置主键生成策略即可.

# 设置数据源类型,数据库信息;
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_study_xiaozhi?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
#加入日志功能;
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  #可配置mybatis的全局配置
  global-config:
    db-config:
      #设置实体类表的统一前缀;
      table-prefix: t_
      #可设置统一的主键生成策略;
      id-type: auto

测试新增数据,可发现执行了自增策略.
在这里插入图片描述


1.3 雪花算法介绍


为应对数据规模的增长,需要分析访问压力和数据量
数据库的三种扩展方式:业务分库、主从复制,数据库分表。

关于数据库分表:
在这里插入图片描述
垂直分表:
在这里插入图片描述
水平分表
在这里插入图片描述
在这里插入图片描述


1.4 @TableField


首先模拟场景,数据表字段用下划线分隔,在实体类中属性用驼峰命名.

将user中的name字段改为user_name.
在这里插入图片描述
在实体类User中也进行修改.

在这里插入图片描述
执行测试方法;

在这里插入图片描述
执行sql时,名称字段还是user_name,那么也就是说在mybatis-plus中有默认的下划线匹配对应驼峰.
在这里插入图片描述


那要是不在实体类中使用驼峰命名法呢?
在这里插入图片描述

执行测试方法,
在这里插入图片描述
在执行sql时,无法识别到对应的字段
在这里插入图片描述


那么,即要不用驼峰命名,还要匹配对应字段,使用注解@TableField即可.

在这里插入图片描述

执行测试方法;已正确识别到字段user_name.
在这里插入图片描述


1.5 @TableLogic


关于逻辑删除,也就是在代码逻辑上数据已经被删除,但是数据库中实际只是改变了数据的状态,数据并没有消除.\

在数据表user中创建一个字段is_deleted,表示该数据行是否删除的转态,默认为0表示未删除,删除时修改该字段即可.

在这里插入图片描述
在实体类User中添加该属性.可用注解@TableLogic表明逻辑删除.
在这里插入图片描述

现在测试执行删除方法;一次性删除3个.
在这里插入图片描述

但是注意到它执行的sql语句并不是delete,而是update更新数据,将字段is_deleted由0变为了1.
在这里插入图片描述


当前的user数据表包含了22条数据,刚才逻辑删除3条.实际总数据应该是19条.
在这里插入图片描述

现在执行查询语句查看总数据量;
在这里插入图片描述
执行后,注意到总数据量为19条. 也就是说,逻辑删除已被认可.
执行的sql也用where来筛选is_deleted为0的数据.
在这里插入图片描述


2. 条件构造器


![在这里插入图片描述](https://img-blog.csdnimg.cn/4f222f0bcb444022a1a0cd3a950269b6.png)

关于条件构造器的说明

Wrapper:条件构造器的抽象类
AbstractWrapper 封装查询条件,可生成sql语句中的where条件.
QueryWrapper封装查询条件
UpdateWrapper封装更新条件
AbstractLambdaWrapper,LambdaQueryWrapper,LambdaUpdateWrapper 可使用Lambda语法


2.1 组装查询条件案例


先创建测试类MybatisPlusWrapperTest ;

import com.xiaozhi.mybatisplus.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
 * @BelongsProject: mybatis-plus
 * @BelongsPackage: com.xiaozhi.mybatisplus
 * @Author: 信计1801 李智青
 * @Date: 2022/7/1 20:27
 * @Description: 条件构造器测试
 */
@SpringBootTest
public class MybatisPlusWrapperTest {
    //自动装配;
    @Autowired
    private UserMapper userMapper;

}

运行测试方法1,查询数据表中,name包含xaiozhi,年龄位于20-50之间,邮箱不为空的用户.

@Test
public void testOne() {
    //查询数据表中,name包含xaiozhi,年龄位于20-50之间,邮箱不为空的用户.
    QueryWrapper<User> queryWrapper = new QueryWrapper();
    queryWrapper.like("user_name", "xiaozhi")
            .between("age", 20, 50)
            .isNotNull("email");
    //查询集合;
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

执行结果;

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)

在这里插入图片描述


2.2 组装排序案例


运行测试方法2;查询用户信息,按年龄进行降序排序.年龄相同,则按照uid排序.

@Test
public void testTwo() {
    //查询用户信息,按年龄进行降序排序.年龄相同,则按照uid排序.
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.orderByDesc("age")
            .orderByAsc("uid");
    //查询集合;
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

运行之;

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASC

在这里插入图片描述


2.3 组装删除条件案例


运行测试方法3:删除user_name为空的数据

@Test
public void testThree() {
    //删除user_name不为空的数据
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.isNotNull("user_name");
    int delete = userMapper.delete(queryWrapper);
    System.out.println("删除了" + delete + "条数据");
}

运行之,实际是逻辑删除.

UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (user_name IS NOT NULL)

在这里插入图片描述


2.4 修改功能案例


测试方法4:修改数据:年龄大于20,用户名包含xiaozhi,或者邮箱为空的用户.

@Test
public void testFour() {
    //修改数据:年龄大于20,用户名包含xiaozhi,或者邮箱为空的用户.
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.gt("age", 20)
            .like("user_name", "xiaozhi")
            .or()
            .isNull("email");
    User user = new User();
    user.setAge(20);
    int update = userMapper.update(user, queryWrapper);
    System.out.println("修改了" + update + "条数据");
}

运行之.

UPDATE t_user SET age=? WHERE is_deleted=0 AND (age > ? AND user_name LIKE ? OR email IS NULL)

在这里插入图片描述


2.5 条件的优先级设置


测试方法5:修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.

注意需要设置条件的优先级,不然写出来就和测试方法4差不多了.

@Test
public void testFive() {
    //修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("user_name", "xiaozhi")
            .and(i -> i.gt("age", 20).or().isNull("email"));
    User user = new User();
    user.setAge(20);
    int update = userMapper.update(user, queryWrapper);
    System.out.println("修改了" + update + "条数据");
}

运行之,实际执行sql为:

UPDATE t_user SET age=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))

在这里插入图片描述


2.6 组装select精确查询案例


测试方法6:查询用户的名称,年龄,邮箱;;

@Test
public void testSix() {
    //查询用户的名称,年龄,邮箱;;
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.select("user_name", "age", "email");
    //查询集合;
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

运行之,实际执行SQL为:

SELECT user_name,age,email FROM t_user WHERE is_deleted=0

在这里插入图片描述


2.7 组装子查询案例


测试方法7:查询uid小于100的用户.

@Test
public void testSeven() {
    //查询uid小于100的用户.
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.inSql("uid", "select uid from t_user where uid < 100");
    //查询集合;
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

运行之,实际执行sql为:

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid < 100))

在这里插入图片描述


2.8 UpdateWrapper的修改功能案例


测试方法8: 修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.

@Test
public void testEight() {
    //修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    updateWrapper.like("user_name", "xiaozhi")
            .and(i -> i.gt("age", "20").or().isNull("email"));
    updateWrapper.set("user_name", "小智RE0").set("age", 22);
    int update = userMapper.update(null, updateWrapper);
    System.out.println("修改了" + update + "条数据");
}

运行之,实际运行SQL为:

UPDATE t_user SET user_name=?,age=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))

在这里插入图片描述


2.9 模拟开发组装条件案例


编写一个模拟数据输入的案例

@Test
public void testNine() {
    //模拟前端输入数据;
    String userName = "xiaozhi";
    Integer ageStart = 22;
    Integer ageEnd = 230;
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //isNotBlank 判断字符串序列不是 null ,不是空白
    if (StringUtils.isNotBlank(userName)) {
        queryWrapper.like("user_name", userName);
    }
    if (ageStart != null) {
        queryWrapper.ge("age", ageStart);

    }
    if (ageEnd != null) {
        queryWrapper.le("age", ageEnd);

    }
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

运行之,实际运行SQL为:

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)

在这里插入图片描述


2.10 使用Condition组装条件案例


测试方法10:

@Test
public void testTen() {
    //模拟前端输入数据;
    String userName = "xiaozhi";
    Integer ageStart = 20;
    Integer ageEnd = 230;
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    //isNotBlank 判断字符串序列不是 null ,不是空白;
    //这里用了布尔类型的参数condition作为判断先行条件;
    queryWrapper.like(StringUtils.isNotBlank("user_name"), "user_name", userName)
            .ge(ageStart != null, "age", ageStart)
            .le(ageEnd != null, "age", ageEnd);
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

运行之,实际执行sql为:

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)

在这里插入图片描述


2.11 LambdaQueryWrapper案例


测试方法11:

@Test
public void testEleven() {
    //模拟前端输入数据;
    String userName = "xiaozhi";
    Integer ageStart = 20;
    Integer ageEnd = 230;
    LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.like(StringUtils.isNotBlank("user_name"), User::getName, userName)
            .ge(ageStart != null, User::getAge, ageStart)
            .le(ageEnd != null, User::getAge, ageEnd);
    List<User> userList = userMapper.selectList(queryWrapper);
    userList.forEach(System.out::println);
}

运行之,实际运行SQL为:

SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age >= ? AND age <= ?)

在这里插入图片描述


2.12 LambdaUpdateWrapper使用案例


测试方法12:

@Test
public void testTwelve() {
    //修改数据: 用户名包含xiaozhi,并且(年龄大于20岁或者邮箱为空的) 用户.
    LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
    updateWrapper.like(User::getName, "xiaozhi")
            .and(i -> i.gt(User::getAge, "20").or().isNull(User::getEmail));
    updateWrapper.set(User::getName, "小智RE0").set(User::getAge, 22);
    int update = userMapper.update(null, updateWrapper);
    System.out.println("修改了" + update + "条数据");
}

运行之,实际SQL为:

UPDATE t_user SET user_name=?,age=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))

在这里插入图片描述


3.Mybatis-Plus分页插件


创建一个配置类即可使用分页插件

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @BelongsProject: mybatis-plus
 * @BelongsPackage: com.xiaozhi.mybatisplus.config
 * @Author: 信计1801 李智青
 * @Date: 2022/7/2 12:47
 * @Description: 分页配置类;
 */
@Configuration
//标注扫描映射接口所在的包;
@MapperScan("com.xiaozhi.mybatisplus.mapper")
public class PaginationConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new
                PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

创建测试类,写一个测试的分页方法试试;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaozhi.mybatisplus.entity.User;
import com.xiaozhi.mybatisplus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * @BelongsProject: mybatis-plus
 * @BelongsPackage: com.xiaozhi.mybatisplus
 * @Author: 信计1801 李智青
 * @Date: 2022/7/2 12:53
 * @Description: 插件测试类
 */
@SpringBootTest
public class PlginTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testOne() {
        //创建分页对象;当前页的页码,当前页的显示条数;
        Page<User> page = new Page<>(2, 5);
        //查询,此处就不放条件了
        Page<User> userPage = userMapper.selectPage(page, null);
        System.out.println(userPage);
    }
}

运行之,分页使用的SQL
SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?

在这里插入图片描述


分页数据获取


  • getRecords()方法 来获取数据列表
  • getCurrent() 获取当前页
  • getPages() 获取总页数
  • getTotal() 获取总记录数
@Test
public void testOne() {
    //创建分页对象;当前页的页码,当前页的显示条数;
    Page<User> page = new Page<>(2, 5);
    //查询,此处就不放条件了
    Page<User> userPage = userMapper.selectPage(page, null);
    //getRecords() 获取数据列表
    System.out.println("getRecords() 获取数据列表----------->");
    System.out.println(userPage.getRecords());
    //getCurrent() 获取当前页
    System.out.println("getCurrent() 获取当前页------------->");
    System.out.println(userPage.getCurrent());
    //getPages() 获取总页数
    System.out.println("getPages() 获取总页数-------------->");
    System.out.println(userPage.getPages());
    //getTotal() 获取总记录数
    System.out.println("getTotal() 获取总记录数------------>");
    System.out.println(userPage.getTotal());
}

在这里插入图片描述


自定义分页功能


UserMapper接口中定义功能方法;

@Repository
public interface UserMapper extends BaseMapper<User> {
    /*自定义测试方法,根据Id查询集合数据*/
    Map<String, Object> selectMapById(Long id);

    //根据年龄查询分页;
    Page<User> selfPage(@Param("page") Page<User> page, @Param("age") Integer age);
}

application.yml中配置对应类型别名.
在这里插入图片描述

UserMapper.xml中编写sql

<?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.xiaozhi.mybatisplus.mapper.UserMapper">
    <!--根据Id查询集合数据-->
    <select id="selectMapById" resultType="map">
            select id,name,age,email from user where id = #{id}
    </select>

    <!--根据年龄查询分页;-->
    <select id="selfPage" resultType="User" >
            select uid,user_name,age,email
            from t_user
            where age >= #{age}
    </select>
</mapper>

PlginTest测试类中写个测试方法2

@Test
public void testTwo() {
    //创建分页对象;当前页的页码,当前页的显示条数;
    Page<User> page = new Page<>(1, 5);
    //根据年龄作为条件进行查询;
    Page<User> userPage = userMapper.selfPage(page, 20);
    System.out.println(userPage);
}

运行之,执行sql
select uid,user_name,age,email from t_user where age >= ? LIMIT ?
在这里插入图片描述


4.乐观锁悲观锁


场景假设
在这里插入图片描述
在这里插入图片描述


模拟修改冲突


首先在数据库中新建一个商品表

CREATE TABLE t_product(
id BIGINT(20) NOT NULL COMMENT '主键ID',
NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',
price INT(11) DEFAULT 0 COMMENT '价格',
VERSION INT(11) DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id)
);

添加数据

INSERT INTO t_product (id, NAME, price) VALUES (1, '小智笔记', 80);

entity目录下创建商品实体类

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

/**
 * @BelongsProject: mybatis-plus
 * @BelongsPackage: com.xiaozhi.mybatisplus.entity
 * @Author: 信计1801 李智青
 * @Date: 2022/7/2 13:49
 * @Description: 商品实体类
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
    //商品Id
    private Long id;
    //商品名
    private String name;
    //商品价格;
    private Integer price;
    //版本号
    private Integer version;
}

mapper目录下创建ProductMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiaozhi.mybatisplus.entity.Product;
import org.springframework.stereotype.Repository;

/**
 * @BelongsProject: mybatis-plus
 * @BelongsPackage: com.xiaozhi.mybatisplus.mapper
 * @Author: 信计1801 李智青
 * @Date: 2022/7/2 13:59
 * @Description: 商品类对应映射类
 */
@Repository
public interface ProductMapper extends BaseMapper<Product> {
    
}

在之前的测试类PlginTest中创建方法模拟冲突进行测试;

@Autowired
private ProductMapper productMapper;

//测试商品表的数据操作;
@Test
public void testProOne() {
    //杰哥根据Id查询商品信息;
    Product AJieRest = productMapper.selectById(1);
    System.out.println("杰哥得到的结果-->" + AJieRest.getPrice() + "元");
    //阿伟根据Id查询商品信息;
    Product AWeiRest = productMapper.selectById(1);
    System.out.println("阿伟得到的结果-->" + AWeiRest.getPrice() + "元");

    //杰哥让商品涨价了50元;
    AJieRest.setPrice(AJieRest.getPrice() + 50);
    productMapper.updateById(AJieRest);
    //阿伟让商品降价20元;
    AWeiRest.setPrice(AWeiRest.getPrice() - 20);
    productMapper.updateById(AWeiRest);

    //彬彬查询商品价格;
    Product BinBinRest = productMapper.selectById(1);
    System.out.println("彬彬得到的结果-->" + BinBinRest.getPrice() + "元");
}

运行之

在这里插入图片描述


乐观锁插件


在实体类中,可使用注解@Version来标注乐观锁字段

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
    //商品Id
    private Long id;
    //商品名
    private String name;
    //商品价格;
    private Integer price;
    //版本号  标注乐观锁.
    @Version
    private Integer version;
}

当然,也需要在PaginationConfig中进行配置

@Configuration
//标注扫描映射接口所在的包;
@MapperScan("com.xiaozhi.mybatisplus.mapper")
public class PaginationConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //添加分页插件
        interceptor.addInnerInterceptor(new
                PaginationInnerInterceptor(DbType.MYSQL));
        //添加乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

注意,测试刚才执行的模拟修改冲突;
在这里插入图片描述


实际也可以在语句中进行判断,

在这里插入图片描述


5.通用枚举


在数据表中有的字段需要使用固定值,则可以使用通用枚举来声明

案例,在数据表t_user中创建性别字段sex;
在这里插入图片描述


那么,既然使用枚举类,则创建一个枚举类型的性别类;
先创建enums目录,然后创建SexEnums

在这里插入图片描述

/**
 * @BelongsProject: mybatis-plus
 * @BelongsPackage: com.xiaozhi.mybatisplus.enums
 * @Author: 信计1801 李智青
 * @Date: 2022/7/4 22:17
 * @Description: 性别描述
 */
 @Getter
public enum SexEnums {
    MALE(1, "男"),
    FEMALE(2, "女");

    private Integer sex;
    private String sexName;

    SexEnums(Integer sex, String sexName) {
        this.sex = sex;
        this.sexName = sexName;
    }
}

在用户类编写sex属性
在这里插入图片描述

可进行测试,创建测试类MybatisEnumTest

import com.xiaozhi.mybatisplus.entity.User;
import com.xiaozhi.mybatisplus.enums.SexEnums;
import com.xiaozhi.mybatisplus.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * @BelongsProject: mybatis-plus
 * @BelongsPackage: com.xiaozhi.mybatisplus
 * @Author: 信计1801 李智青
 * @Date: 2022/7/4 22:23
 * @Description: 通用枚举测试类
 */
@SpringBootTest
public class MybatisEnumTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testOne() {
        User user = new User();
        user.setName("小智W");
        user.setAge(22);
        user.setEmail("xaiozhi@qq.com");
        user.setSex(SexEnums.MALE);
        int insert = userMapper.insert(user);
        System.out.println("成功插入" + insert + "条数据");
    }
}

运行之,此时出现问题:
在这里插入图片描述
注意使用注解@EnumValue将该性别属性存入数据库中;
在这里插入图片描述
当然,需要配置到yml文件中配置扫描通用枚举类

type-enums-package:

在这里插入图片描述
此时运行无问题

在这里插入图片描述


6 代码生成器


先引入依赖

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

创建快速生成测试类FastAutoGeneratorTest

public class FastAutoGeneratorTest {
    public static void main(String[] args) {
        FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL = false", "root", "123456")
                .globalConfig(builder -> {
                    builder.author("atguigu") // 设置作者
                             //.enableSwagger() // 开启 swagger 模式
                            .fileOverride() // 覆盖已生成文件
                            .outputDir("F://mybatis_plus_auto"); // 指定输出目录
                })
                .packageConfig(builder -> {
                    builder.parent("com.xiaozhi") // 设置父包名
                            .moduleName("mybatisplus") // 设置父包模块名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://mybatis_plus"));
                    // 设置mapperXml生成路径
                })
                //策略配置
                .strategyConfig(builder -> {
                    builder.addInclude("t_user") // 设置需要生成的表名
                            .addTablePrefix("t_", "c_"); // 设置过滤表前缀
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker 引擎模板,默认的是Velocity引擎模板
                .execute();
    }

}

运行之,即可生成项目


7.mybatis-X插件生成代码

快速创建一个新的项目

在这里插入图片描述
创建yml配置文件application.yml,存入基础的数据源配置

# 设置数据源类型,数据库信息;
spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_study_xiaozhi?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
    username: root
    password: 数据库密码
    driver-class-name: com.mysql.cj.jdbc.Driver

注意将数据库连接

在这里插入图片描述

对数据库选择MybatisX构造
在这里插入图片描述

配置
在这里插入图片描述
在这里插入图片描述

生成目录成功

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小智RE0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值