一篇文章带你学会MybatisPlus~(三)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 一篇文章带你学会MybatisPlus~

一篇文章带你学会MybatisPlus~(二):https://developer.aliyun.com/article/1424742

自定义分页功能:

第一步:在mapper接口中编写方法:

//@Param Page是MybatisPlus所提供的分页对象,必须位于第一个参数的位置
    //通过年龄查询用户信息并分页
    Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);

在resources目录下创建对应的映射文件编写sql语句—映射语句中我们并没有书写分页功能

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatisplus.Mapper.UserMapper">
    <select id="selectPageVo" resultType="User">
    <!--当前我们编写的sql语句并 -->
        select * from t_user where age>#{age}
    </select>
</mapper>

测试类:

package com.example.mybatisplus.Test;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.mybatisplus.Mapper.UserMapper;
import com.example.mybatisplus.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MybatisPlusPluginsTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void testPage() {
        Page<User> userPage = new Page<>(1, 3);
        userMapper.selectPageVo(userPage,15);
        //输出的查询到的所有记录数
        System.out.println(userPage.getRecords());
        //获取总页数
        System.out.println(userPage.getPages());
        //获取总记录条数
        System.out.println(userPage.getTotal());
        //判断是否还有下一页
        System.out.println(userPage.hasNext());
        //判断是否还有上一页
        System.out.println(userPage.hasPrevious());
    }
}

输出如下所示:

乐观锁:

一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小李正在玩游戏,耽搁了一个小时。1个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元。

此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就完全被小王的覆盖了。

现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1万多


上面的故事


如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过了,则重新取出的被修改后的价格,150元,这样他会将120元存入数据库。


如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证最终的价格是120元。

模拟修改冲突:

创建表:

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,"外星人笔记本",100);

创建实体类:

package com.example.mybatisplus.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Product {
    private Integer id;
    private String name;
    private Integer price;
    private Integer version;
}

创建对应的接口:

package com.example.mybatisplus.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mybatisplus.pojo.Product;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductMapper extends BaseMapper<Product> {
}

编写测试类:

package com.example.mybatisplus.Test;
import com.example.mybatisplus.Mapper.ProductMapper;
import com.example.mybatisplus.pojo.Product;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MybatisPlusTest {
    @Autowired
    private ProductMapper productMapper;
    @Test
    public void test(){
            //小李查询商品价格
            Product productLi=productMapper.selectById(1);
            System.out.println("小李查询商品的价格"+productLi.getPrice());
            //小王查询商品价格
            Product productWang=productMapper.selectById(1);
            System.out.println("小王查询商品的价格"+productLi.getPrice());
            //小李修改商品
            productLi.setPrice(productLi.getPrice()+50);
            productMapper.updateById(productLi);
            //小王将商品价格-30
            productWang.setPrice(productWang.getPrice()-30);
            productMapper.updateById(productWang);
            //老板查询的商品价格
            Product productboss=productMapper.selectById(1);
            System.out.println("老板查询的商品价格:"+productboss.getPrice());
    }
}

输出如下所示:

使用乐观锁插件:

在配置类中添加乐观锁插件:

mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

在实体类的对应字段加入表示版本号的注解:

此时重新运行上述的方法,输出如下所示:

//当小王的影响的记录数为0时,那么则出现和上述相同小王修改失败的现象,我们需要先获取最新的价格,再将最新的价格减少30
if(result==0){
            Product productNew=productMapper.selectById(1);
            productNew.setPrice(productNew.getPrice()-30);
            productMapper.updateById(productNew);
            }

注意:在进行新的测试之前需要把数据库表中version重新设置为0,price设置成100

输出如下所示:

通用枚举:

表中的有些字段值是固定的,例如性别(男或者女),此时我们可以使用mybatis-plus的通用枚举来实现

创建枚举类用来表示性别:

package com.example.mybatisplus.Enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;
@Getter
public enum SexEnums {
    MALE(1,"男"),
    FEMALE(2,"女");
    @EnumValue//僵住解锁表示的属性的值直接放入数据库中
    private Integer sex;
    private String sexName;
    SexEnums(Integer sex, String sexName) {
        this.sex = sex;
        this.sexName = sexName;
    }
}

在实体类User中添加枚举类型:

注意:这里枚举类型的属性值必须和数据库表中字段值相同,否则会出现匹配不到对应的列

在application.yaml文件中配置扫描通用枚举的包

mybatis-plus:
  type-enums-package: com.example.mybatisplus.Enums

编写测试类:

package com.example.mybatisplus.Test;
import com.example.mybatisplus.Mapper.UserMapper;
import com.example.mybatisplus.Enums.SexEnums;
import com.example.mybatisplus.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class MybatisPlusEnumsTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void test1() {
        User user = new User();
        user.setName("蓝月亮");
        user.setEmail("lanyueliang@qq.com");
        user.setAge(30);
        user.setSex(SexEnums.FEMALE);
        int result=userMapper.insert(user);
        System.out.println(result);
    }
}

输出如下所示:

多数据源:

适用于多种场景:纯粹多库,读写分离,一主多从,混合模式

下面我们就来模拟纯粹多库的场景

场景说明:

我们创建两个库,分别为mybatisplusmybatisplus1,将mybatisplus库的product表移动到mybatisplus1库,这样每个库一张表,通过一个测试用例分别获取用户数据与商品数据,如果获取到说明多库模拟成功

导入对应的依赖:

<dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
      <version>3.5.0</version>
    </dependency>

创建从数据库mybatisplus1:

CREATE DATABASE  mybatisplus1;
use mybatisplus1 ;
CREATE TABLE 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 product values(1,"外星人笔记本",100,0);

application.yaml中配置数据源的信息:

spring:
  # 配置数据源信息
  datasource:
    dynamic:
  # 设置默认的数据源或者数据源组,黑认值即为master
      primary: master
  # 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,fase使用默认数据源
      strict: false
      datasource:
        master :
          url: jdbc:mysql://localhost:3306/mybatisplus?characterEncoding=utf-8
          driver-class-name: com.mysql.cj.jdbc.Driver
          username: root
          password: 你的密码
          slave_1:
            ur]: jdbc:mysql://localhost:3306/mybatisplus1?characterEncoding=utf-8
            driver-class-name: com.mysql .cj.jdbc.Driver
            username: root
            password: 你的密码

创建用户service:

package com.example.mybatisplus.Service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mybatisplus.pojo.User;
public interface UserService extends IService<User> {
}

UserService对应的实现类:

package com.example.mybatisplus.Service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mybatisplus.Mapper.UserMapper;
import com.example.mybatisplus.Service.UserService;
import com.example.mybatisplus.pojo.User;
import org.springframework.stereotype.Service;
@DS("master")//指定UserServiceImpl操作的数据库为@DS
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
}

创建产品service:

package com.example.mybatisplus.Service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mybatisplus.pojo.Product;
public interface ProductService extends IService<Product> {
}

创建产品service对应的实现类:

package com.example.mybatisplus.Service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mybatisplus.Mapper.ProductMapper;
import com.example.mybatisplus.Service.ProductService;
import com.example.mybatisplus.pojo.Product;
import org.springframework.stereotype.Service;
@DS("slave_1")//指定UserServiceImpl操作的数据库为slave_1
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
}

创建User对应的Mapper接口:

package com.example.mybatisplus.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mybatisplus.pojo.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {
}

创建Product对应的Mapper接口:

package com.example.mybatisplus.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mybatisplus.pojo.Product;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductMapper extends BaseMapper<Product> {
}

编写测试方法:

package com.example.mybatisplus.Test;
import com.example.mybatisplus.Service.ProductService;
import com.example.mybatisplus.Service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class MybatisPlusApplicationTests {
  @Autowired
  private UserService userService;
  @Autowired
  private ProductService productService;
  @Test
  public void test(){
    //service对数据库进行操作为了区分mapper对数据进行操作,所有查询操作都是以get开头
    System.out.println(userService.getById(1));
    System.out.println(productService.getById(1));
  }
}

输出如下所示:

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
Java Spring 容器
Spring系列文章:Spring6集成MyBatis3.5
Spring系列文章:Spring6集成MyBatis3.5
|
4月前
|
存储 算法 Java
一篇文章带你学会MybatisPlus~(二)
一篇文章带你学会MybatisPlus~
|
4月前
|
SQL Java 数据库连接
一篇文章带你学会MybatisPlus~(一)
一篇文章带你学会MybatisPlus~
|
6月前
|
SQL Java 数据库连接
一般文章让你了解mybatis,以及如今在Java开发的地位!
一般文章让你了解mybatis,以及如今在Java开发的地位!
|
SQL XML 存储
Java文章没python文章火?,我反手整理一套MyBatis面试题(建议收藏)(三)
Java文章没python文章火?,我反手整理一套MyBatis面试题(建议收藏)
44 0
|
SQL 存储 缓存
Java文章没python文章火?,我反手整理一套MyBatis面试题(建议收藏)(二)
Java文章没python文章火?,我反手整理一套MyBatis面试题(建议收藏)
79 0
Java文章没python文章火?,我反手整理一套MyBatis面试题(建议收藏)(二)
|
SQL XML 缓存
Java文章没python文章火?,我反手整理一套MyBatis面试题(建议收藏)(一)
Java文章没python文章火?,我反手整理一套MyBatis面试题(建议收藏)
105 0
Java文章没python文章火?,我反手整理一套MyBatis面试题(建议收藏)(一)
|
SQL 存储 XML
面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他(四)
MyBatis 是第一个支持自定义 SQL、存储过程和高级映射的类持久框架。MyBatis 消除了大部分 JDBC 的样板代码、手动设置参数以及检索结果。MyBatis 能够支持简单的 XML 和注解配置规则。使 Map 接口和 POJO 类映射到数据库字段和记录。
78 0
面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他(四)
|
SQL 存储 设计模式
面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他(三)
MyBatis 是第一个支持自定义 SQL、存储过程和高级映射的类持久框架。MyBatis 消除了大部分 JDBC 的样板代码、手动设置参数以及检索结果。MyBatis 能够支持简单的 XML 和注解配置规则。使 Map 接口和 POJO 类映射到数据库字段和记录。
66 0
面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他(三)
|
SQL 监控 druid
看完这篇文章,你也可以手写MyBatis部分源码(JDBC)(下)
JDBC (Java DataBase Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,(java.sql,javax.sql)使用这些类库可以以一种标准的方法、方便地访问数据库资源。
143 0
看完这篇文章,你也可以手写MyBatis部分源码(JDBC)(下)