首页 > 其他分享 >【02】手把手教你0基础部署SpringCloud微服务商城教学-Mybatis篇(下)

【02】手把手教你0基础部署SpringCloud微服务商城教学-Mybatis篇(下)

时间:2024-10-11 23:22:45浏览次数:3  
标签:02 01 07 SpringCloud 查询 user 2023 Mybatis 我们

上期回顾:【01】手把手教你0基础部署SpringCloud微服务商城教学-Mybatis篇(上)

Part1.续接上文Mybatis-plus的批处理功能

接下来我们学习一下IService的批量查询,我们用以往的for循环做一个对比

这是for循环部分的代码

    private User builderUser(int i){
        User user=new User();
        user.setUsername("user_"+i);
        user.setPassword("123456");
        user.setPhone(""+(100000000L+i));
        user.setBalance(2000);
        user.setInfo("{\"age\":24,\"info\":\"英文老师\",\"gender\":\"female\"}");
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(user.getCreateTime());
        return user;
    }
    @Test
    void testSaveOneByOne(){
        long b=System.currentTimeMillis();
        for(int i=0;i<100000;i++){
            userService.save(builderUser(i));
        }
        long e=System.currentTimeMillis();
        System.out.println("耗时:"+(e-b));
    }

这是我们的耗时达到了十九万毫秒,可以看到效率还是非常差的,现在查看数据库会发现插入了非常多条的数据。

我们现在把id>9的数据都删掉。

ok,我们删除完数据后,用IService的批处理来尝试一下,看看性能会不会好一点。

如下是新的测试代码:

 @Test
    void testSaveBatch(){
        //我们每次批量插入1000条,插入100次即插入10万条数据
        //1.我们准备一个容量为1000的集合,创建1000个User对象
        List<User> list=new ArrayList<>(1000);
        long b=System.currentTimeMillis();
        for(int i=0;i<=100000;i++){
            //2.添加一个user
            list.add(builderUser(i));
            //3.每次插入1000条,执行一次批量插入
            if(i%1000==0){
                userService.saveBatch(list);
                //4.清空集合,准备下一批数据
                list.clear();
            }
        }
        long e=System.currentTimeMillis();
        System.out.println("耗时:"+(e-b));
    }

我们可以看到耗时从十九万骤降到一万八,差不多十倍的效率。

但是我们如果仍然觉得慢,我们就开始思考,通过查看底层代码

通俗的讲,老旧的for循环相当于是一次次插入数据,插入了一万次,而利用IService的方法,我们把一万次拆分成了一百个一千次。

而通过查看底层代码发现其实mp的批处理是基于PrepareStatement的预编译模式,然后批量提交,最终在数据库执行时还是会有多条insert语句,逐条插入数据。SQL类似这样:

Preparing: INSERT INTO user ( username, password, phone, info, balance, create_time, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )
Parameters: user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01
Parameters: user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01
Parameters: user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01

如果我们想更快一点,最好将多条SQL语句合并为一条,像这样:

INSERT INTO user ( username, password, phone, info, balance, create_time, update_time )
VALUES 
(user_1, 123, 18688190001, "", 2000, 2023-07-01, 2023-07-01),
(user_2, 123, 18688190002, "", 2000, 2023-07-01, 2023-07-01),
(user_3, 123, 18688190003, "", 2000, 2023-07-01, 2023-07-01),
(user_4, 123, 18688190004, "", 2000, 2023-07-01, 2023-07-01);

那该如何做到呢?

我们需要开启rewriteBatchedStatements=true参数。

这个配置Mybatis3.13之后都是有的,不是mp做的。

自己拼一个数据,完整代码如下:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456

可以看到这个时候我们的耗时就变成了7700多,相比于开始的十九万是极其巨大的提升。

Part2.代码生成功能

我们以往的开发业务中,一般是先定义一个实体类如User类,然后去写它的mapper,然后写service接口,serviceImpl类。

我们在业务开发中的代码大部分是固定的,只有类的名字发生变化。

这个时候我们可以引入一个同名叫MybatisPlus的插件。

然后注意,新版的idea是把other这个功能栏改进到了Tools里

写到这里,我们打开config Database会出现一个时区的错误。

The server time zone value 'йʱ' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.

我在网上进行了无数的搜索,有让改my.ini的。

也有说需要去下载时区补丁的,总之杂七杂八非常混乱。

在这我分说一下几个问题,如果这个时候我们问AI,它会有显示sh语句和sql语句,sh语句就是我们在cmd命令行里输入的,sql语句就是在数据库里执行的。

而且my.ini的位置非常不好找,

如图我的mySQL是在这两个里面分别有一个,但是包括我们在系统服务等功能里去寻找定位的时候,全部都是定位到Program Files下的mySQL,而最逆天的就是这个文件目录下的MySQL是没有my.ini的,无论是MySQL的根目录还是bin目录全都没有,这个时候你就要注意了。

你可能和我一样把文件和配置文件分开保管了,也不要去去跟着网上的教程搞什么自己新建一个ini,包括停止重启数据库这些操作,因为我已经把雷都趟完了,根本没用,下图可证我是真搞了一遍。

那么实际的解决办法居然简单的出乎意料,那就是你直接把yaml文件里的url地址拷贝一份直接复制到config database中,这时候你再进行测试,就直接显示成功了,后续插件的功能也能正常使用。

然后我们打开Code Generator

检查一下是否生成成功

咱们所有的配置都生成好了,不用自己写了,包括service继承什么都写好了。

Part3.静态工具Db

静态工具类是没有泛型的,我们就需要传id和实体类,那其他的地方都和前文讲过的IService接口是一样的,那我们为啥要用Db呢?

我们通过一个案例来解答这个疑惑。

案例需求:

①改造根据id查询用户的接口,查询用户的同时,查询出用户对应的所有地址

②改造根据id批量查询用户的接口,查询用户的同时,查询出用户对应的所有地址

有的时候Service之间也会相互调用,为了避免出现循环依赖问题,所以我们要用到Db。

循环依赖类似于死锁,如果现在有两个实例化的bean都在等对方的实例化,就导致对方看不到自己初始化的bean而不停等待实例化的bean,但三级缓存使初始化也能被看到从而解决了问题。

首先我们导入准备好的AdressVO。

在UserVO里新增一个收货地址

然后在Controller里直接重新写方法

Service里定义新方法

ServiceImpl里实现新方法

代码如下:

 @Override
    public UserVO queryUserAndAddressById(Long id) {
        //1.查询用户
        User user = getById(id);
        if(user==null||user.getStatus()==2){
            throw new RuntimeException("用户状态异常!");
        }
        //2.查询用户地址
        List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getUserId, id).list();
        //3.封装VO
        //3.1转User的PO为VO
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        //3.2转Address的PO为VO
        if (CollUtil.isNotEmpty(addresses)){
            userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class));
        }
        return userVO;
    }

然后我们启动SpringBoot测试一下

功能是正常的。

我们再来写第二个,因为前面的各个包里建的东西完全一样,所以我在这块只贴上实现类中的代码。

    @Override
    public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {
        //1.查询用户
        List<User> users = listByIds(ids);
        if(CollUtil.isEmpty(users)){
            return Collections.emptyList();
        }
        //2.查询用户地址
        //2.1获取用户id集合
        List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());
        //2.2根据用户id集合查询地址
        List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();
        //2.3转换地址VO
        List<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);
        //2.4梳理地址集合,分类整理,相同用户放入一个集合
        Map<Long,List<AddressVO>> adressMap=new HashMap<>();
        if (!CollUtil.isEmpty(addressVOList)) {
            adressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));
        }
        //3.转换VO返回
        List<UserVO> list=new ArrayList<>(users.size());
        for (User user : users){
            //3.1转换用户PO为VO
            UserVO vo = BeanUtil.copyProperties(user, UserVO.class);
            list.add(vo);
            //3.2转换地址PO为VO
            vo.setAddresses(adressMap.get(user.getId()));
        }
        return list;
    }

然后我们现在测试一下!

启动SpringBoot,打开网页。

然后出现了一个问题就是地址全是NULL???

然后仔细排查代码发现:

修改之后我们测试一下就发现完全OK了。

Part4.逻辑删除

逻辑删除就是基于代码逻辑模拟删除效果,但并不会真正删除数据。

那什么情况下会用到逻辑删除呢?

答:比如淘宝店的订单数据,我们做数据分析都是很宝贵的,那删除不可能真的从物理层面上删除,只能是逻辑上删除。

思路如下:

①在表中添加一个字段标记为数据是否被删除

②当删除数据时把标设为1

③查询时只查询标记为0的数据。

例如逻辑删除字段为deleted:

删除操作:

UPDATE user SET deleted=1 where id=1 AND deleted=0

查询操作:

SELECT*FROM user WHERE deleted=0

当然如果我们一条一条改那也太麻烦了,mp已经帮我们提供了逻辑删除的功能,我们无需改变方法调用的方式,而是底层帮我们自动修改CRUD语句。

我们只需要在application.yaml文件中配置逻辑删除的字段名称和值即可。

然后我们现在修改一下yaml

现在让我们来试一试新功能吧!

写一个删除写一个查询

我们删除成功了,所以查询不到,返回了一个NULL。

总结:逻辑删除本身也有自己的问题→

比如会导致数据库的垃圾数据越来越多,影响查询效率

SQL中全都需要对逻辑删除字段做判断,影响查询效率

因此,不太推荐采用逻辑删除功能,如果数据不能删除,可以采用数据迁移把他移到别的表。

Part5.枚举处理器

User类中有一个用户状态字段,现在的状态还比较少,只有1和2,那如果以后状态类型非常多,我们很难全都靠大脑记住,那么该怎么解决呢?

我们就可以定义一个枚举类型。

直接用枚举类型代替Integer。

枚举是可以直接用==来进行比较的,这样我们代码中就不会有莫名其妙的一堆1和0,1和2进行比较了,而是一堆字段进行比较,我们代码的可读性就变好了。

但是方便也带来了一个问题,就是我们数据库表中关于status的定义还是INT类型。那我们就涉及到一个类型的相互转换,而这里面的所有类型转换都是Mybatis来在底层完成的。

而mp对这些处理器都做了拓展,我们现在解决这个问题就好办了,用现成的处理器就OK了。

第一件事,我们框框用注解标记就完事了。

第二件事,我们直接在application.yaml里配置一个全局枚举处理器就完事。

然后让我们使用一下吧

1.我们先把User里面的状态类型改一下

然后会发现有文件报错了,我们打开一看

进行一下小小的修改

我们启动SpringBoot,打开网页试一下。

Part6.JSON处理器

我们定义一个UserInfo类来代替String info。

但很遗憾mp终究不是万能的,这个时候我们就需要自己写一个JSON类型处理器了。

我们要做两件事

第一件事添加注解

第二件事给注解加加料,开启自动映射

我们会发现UserTest里这时候会有一堆报错,因为以前我们是手搓,现在需要用UserInfo方法去构建。

在这里我根据黑马的课发现如果直接写UserInfo.of的话,of会报错,我搜了一下也没找到原因,可能是mybatis的版本问题。

为了解决这个问题,我采用了一个比较笨拙的办法,就是自己去UserInfo中写一个of方法,代码如下:

这个时候我们就发现我们的整个程序都不会报错了。

现在我们直接alt+8去启动SpringBoot,来到网页做一下测试

我们的info已经从以前的一长串String变成这种样子了。

Part7.分页查询

MybatisPlus给我们提供了非常多的各种各样的功能的插件,但是我们大部分用不太上,所以我们就介绍一个分页插件。

1.首先我们要定义一个配置类,在配置类里注册Mp的核心插件,同时添加分页插件。

2.然后我们现在就可以去搞一个测试类试一下分页功能了。

我们编写完测试代码如果和我一样发现疯狂爆红,别慌张。

有可能是导包出现了问题

解决方法如下:

然后看看测试的那段代码

一切正常了。

我们现在做一下运行测试:

我们分页查询到的结果是正确的,没有问题。

感谢阅读。

标签:02,01,07,SpringCloud,查询,user,2023,Mybatis,我们
From: https://blog.csdn.net/Bew1tch/article/details/142865451

相关文章

  • python学习第二天(2024.10.11)
    python下载官网https://www.python.org/点击Downloads选择安装版本,选择操作系统选择操作系统位数,选择下载文件格式(ZIP、exe)下载安装(安装路径不能有中文和空格)验证是否安装成功win+r,输入cmd,直接输入python,显示正确安装版本及安装成功环境变量配置......
  • 105th 2024/10/11 模拟赛总结61
    傲慢,凭什么傲慢T1开幕雷击,认为水飞了”一眼CDQ板子啊“然后十五分钟时直接开打主要原因绝对是因为昨天场切了T1,所以飘起来了还是应该稳重一点,起码模几个不同数据再下定论实际上也真是水题,相当于板子了自己对排列不够熟悉,真的没想到是直接全局-部分正难则反?从没用上过自以......
  • 104th 2024/10/8 模拟赛总结60
    T1有感觉,因为AB组一起打,所以下意识认为是水题(实际上也不算难?)就直接开始想从深向浅直接扫一遍,能转就转显然错,从浅向深扫一遍同样不对,因为不知道往上转移的顺序比如,设该点为x,是0,有的儿子可能转移到x,其子树内转移的次数比另一个儿子多,所以就要优先它不好处理,看到数据,给了一档2e5,一......
  • Photoshop2024下载安装包(附安装教程)
    Photoshop2024安装包:Photoshop2024安装包百度网盘下载PS2024安装教程:1、右击【PS2024.zip】,选择【解压到PS2024】2、右击【Set-up.exe】,选择【以管理员身份运行】3、点击右下角灰色的小文件夹图标,选择【更改位置】4、选择安装路径后,点击【确定】,然后点击【继......
  • ### 100th 2024/9/8 WQS二分小结
    破百了,路长了这个世界,能听见我的回响吗?循环了很久很久的Echoism回望了过去,也要认真注视当下的现实了对吗?来看看WQS二分可以用上的题目有Raper,Gmoj的coffee和划分序列这几题都有一个共同的特点,就是要从n个中恰好选k个的极值而他们的取值都有一个共性,就是关于k,该函数的形状......
  • 103rd 2024/9/24 斜率优化
    总算是补上了很久之前的坑,一直没学,之前一直不肯动脑子?思路可以从简单的进行入手对于部分DP,若转移是\(i\)从一个\(j\)转移过来,且转移具有单调性,切极为明显,形如\(f_i=max(f_i,f_j+b_j+a_i)\)那么显然可以直接求之前的最值,用一个max记录即可但是有时候会出现跟双方都有关的贡献项......
  • The 2022 ICPC Asia Hangzhou Regional Programming Contest K. Master of Both
    题目链接题意:给定n个字符串,然后给定q种字典序规则,在这q种字典序规则下求出这n个字符串的逆序对数量。思路:我们发现q很大,对于每一种排序规则都遍历一遍n个字符串去求逆序对的数量复杂度太高,所以考虑预处理。我们知道要判断两个字符串字典序的大小关系,只需要知道它们第......
  • 2024金山云武汉招聘岗位
    https://wh.bendibao.com/job/202481/181581.shtm 公司介绍:金山云创立于2012年,作为中国知名的独立云服务商,业务范围遍及全球多个国家和地区。2020年5月金山云在美国纳斯达克上市(股票代码:KC.NASDAQ);2022年12月,以介绍形式于香港交易所主板完成双重主要上市(股票代码:3896.HK)。......
  • mac安装ps2023
    花了5毛钱从网上找的资源下载的,真累啊,找了好久https://www.123pan.com/s/65fKVv-fekWA1、安装时提示error2、包内容中打开install2、错误码501安装错误原因:Mac系统缺少ACC云运行框架,导致安装报错!3、错误码81adobecreateclould退出登录账号;......
  • 安徽省关于做好2024年度全省职称评审工作的通知
    皖人社秘〔2024〕165号各市及广德市、宿松县人力资源社会保障局,省直有关单位: 为贯彻人才兴皖工程部署,落实国家和省关于深化职称制度及人才评价机制改革精神,加快专业技术人才队伍建设,按照《职称评审管理暂行规定》(人社部令第40号)和《安徽省职称评审工作实施办法》(皖人社发〔......