redis缓存单体服务测试本地锁失效问题

news2024/11/23 15:24:36

测试1:锁释放之后向redis缓存存入数据

在这里插入图片描述

//TODO 产生堆外内存溢出 OutOfDirectMemoryError
    //gulimall.com查询分类
    @Override
    public Map<String, List<CategoryLevel2Vo>> getCatelogJson() {
        /**
         * 问题 :解决办法
         * 1.缓存穿透 高并发情况下查询缓存不存在的数据导致并发查数据库    解决办法:查询数据库结果为null时,在缓存中设置不为null的空值(0,1),并设置过期时间,保证缓存能查到该数据
         * 2.缓存雪崩 高并发情况下查询时,因为key设置相同的过期时间而key集体失效     解决办法:给key设置随机过期时间,防止集体失效 set("categoryJson",s,1,xxx)
         * 3.缓存击穿 高并发情况下同时访问同一个Key   解决办法:加锁
         */

        String categoryJson = stringRedisTemplate.opsForValue().get("categoryJson");
        //缓存为空就查数据库
        if (StringUtils.isEmpty(categoryJson)){
            System.out.println("缓存未命中,查数据库");
            //查数据库
            Map<String, List<CategoryLevel2Vo>> fromData = getCatelogJsonFromData();
            //存入redis
            String s = JSON.toJSONString(fromData);
            stringRedisTemplate.opsForValue().set("categoryJson",s,1, TimeUnit.DAYS);
            return fromData;
        }
        System.out.println("缓存命中,直接返回");
        //缓存有数据直接返回缓存数据
        Map<String, List<CategoryLevel2Vo>> object = JSON.parseObject(categoryJson, new TypeReference<Map<String, List<CategoryLevel2Vo>>>() {});
        return object;
    }

查数据库逻辑

//Map<一级分类id,二级分类集合>
    public Map<String, List<CategoryLevel2Vo>> getCatelogJsonFromData() {

        synchronized (this) {
            /**
             * 这种加锁,此项目只部署在一台服务器的情况下可以,本地锁锁住一个实例
             * 分布式情况下就不行,此项目部署在多台服务器上吗,每个锁锁住自己的实例只放一个线程进来
             * 如果8太服务器就会有8个线程同时访问,失去了锁的作用
             * 本地锁只能锁住当前进程,不能锁住其他服务
             *
             */
            //TODO 本地锁(当前进程锁)synchronized 、 (JUC)Lock  ,分布式情况下必须使用分布式锁
            //下一个线程拿到锁之后先查缓存,缓存中没有再查数据库,避免频繁查库
            String categoryJson = stringRedisTemplate.opsForValue().get("categoryJson");
            if (StringUtils.isNotBlank(categoryJson)){
                Map<String, List<CategoryLevel2Vo>> object = JSON.parseObject(categoryJson, new TypeReference<Map<String, List<CategoryLevel2Vo>>>() {});
                return object;
            }
            System.out.println("当前进程锁查询了数据库");
            List<CategoryEntity> categoryGetAll = baseMapper.selectList(null);
            //一级分类
            List<CategoryEntity> category1Level = getParentCid(categoryGetAll,0L);
            Map<String, List<CategoryLevel2Vo>> collect = category1Level.stream().collect(Collectors.toMap(item -> item.getCatId().toString()
                    , l1 -> {
                        //二级分类
                        List<CategoryEntity> category2Level = getParentCid(categoryGetAll,l1.getCatId());
                        List<CategoryLevel2Vo> collect2 = null;
                        if (category2Level != null){
                            collect2 = category2Level.stream().map(l2 -> {
                                //三级分类
                                List<CategoryEntity> category3Level = getParentCid(categoryGetAll,l2.getCatId());
                                List<CategoryLevel2Vo.CategoryLevel3Vo> collect3 = null;
                                if (category3Level != null){
                                    collect3 = category3Level.stream().map(level3 -> {
                                        return new CategoryLevel2Vo.CategoryLevel3Vo(l2.getCatId().toString(),level3.getCatId().toString(),level3.getName());
                                    }).collect(Collectors.toList());
                                }
                                return new CategoryLevel2Vo(l1.getCatId().toString(),collect3,l2.getCatId().toString(),l2.getName());
                            }).collect(Collectors.toList());
                        }
                        return collect2;

                    }));
            return collect;

        }

    }

JMeter性能压测

测试环境

  • 测试之前清空redis缓存
  • 因为是在本地服务器上面运行,单体应用服务器测试进程锁synchronized,实例对象为当前服务(数量:1)
  • 测试线程数:100

预期结果:只查询一次数据库,根据逻辑,如果控制台只打印一次 “当前进程锁查询了数据库” 代表成功

在这里插入图片描述

在这里插入图片描述
测试结果
线程锁测试失败,两次查询数据库,打印了两次 “当前进程锁查询了数据库”

缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
当前进程锁查询了数据库
缓存未命中,查数据库
缓存未命中,查数据库
2023-06-04 00:05:18.208  INFO 6348 --- [io-10001-exec-7] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
2023-06-04 00:05:18.297  INFO 6348 --- [io-10001-exec-7] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
缓存未命中,查数据库
2023-06-04 00:05:18.304 DEBUG 6348 --- [io-10001-exec-7] c.a.g.p.dao.CategoryDao.selectList       : ==>  Preparing: SELECT cat_id,name,parent_cid,cat_level,show_status,sort,icon,product_unit,product_count FROM pms_category WHERE show_status=1 
缓存未命中,查数据库
2023-06-04 00:05:18.316 DEBUG 6348 --- [io-10001-exec-7] c.a.g.p.dao.CategoryDao.selectList       : ==> Parameters: 
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
2023-06-04 00:05:18.344 DEBUG 6348 --- [io-10001-exec-7] c.a.g.p.dao.CategoryDao.selectList       : <==      Total: 1425
当前进程锁查询了数据库
2023-06-04 00:05:18.351 DEBUG 6348 --- [o-10001-exec-42] c.a.g.p.dao.CategoryDao.selectList       : ==>  Preparing: SELECT cat_id,name,parent_cid,cat_level,show_status,sort,icon,product_unit,product_count FROM pms_category WHERE show_status=1 
2023-06-04 00:05:18.351 DEBUG 6348 --- [o-10001-exec-42] c.a.g.p.dao.CategoryDao.selectList       : ==> Parameters: 
缓存未命中,查数据库
2023-06-04 00:05:18.365 DEBUG 6348 --- [o-10001-exec-42] c.a.g.p.dao.CategoryDao.selectList       : <==      Total: 1425
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回

测试2:锁释放之前向redis缓存存入数据

修改代码,在锁释放前存入redis

//TODO 产生堆外内存溢出 OutOfDirectMemoryError
    //gulimall.com查询分类
    @Override
    public Map<String, List<CategoryLevel2Vo>> getCatelogJson() {
        /**
         * 问题 :解决办法
         * 1.缓存穿透 高并发情况下查询缓存不存在的数据导致并发查数据库    解决办法:查询数据库结果为null时,在缓存中设置不为null的空值(0,1),并设置过期时间,保证缓存能查到该数据
         * 2.缓存雪崩 高并发情况下查询时,因为key设置相同的过期时间而key集体失效     解决办法:给key设置随机过期时间,防止集体失效 set("categoryJson",s,1,xxx)
         * 3.缓存击穿 高并发情况下同时访问同一个Key   解决办法:加锁
         */

        String categoryJson = stringRedisTemplate.opsForValue().get("categoryJson");
        //缓存为空就查数据库
        if (StringUtils.isEmpty(categoryJson)){
            System.out.println("缓存未命中,查数据库");
            //查数据库
            Map<String, List<CategoryLevel2Vo>> fromData = getCatelogJsonFromData();
            return fromData;
        }
        System.out.println("缓存命中,直接返回");
        //缓存有数据直接返回缓存数据
        Map<String, List<CategoryLevel2Vo>> object = JSON.parseObject(categoryJson, new TypeReference<Map<String, List<CategoryLevel2Vo>>>() {});
        return object;
    }

    //Map<一级分类id,二级分类集合>
    public Map<String, List<CategoryLevel2Vo>> getCatelogJsonFromData() {

        synchronized (this) {
            /**
             * 这种加锁,此项目只部署在一台服务器的情况下可以,本地锁锁住一个实例
             * 分布式情况下就不行,此项目部署在多台服务器上吗,每个锁锁住自己的实例只放一个线程进来
             * 如果8太服务器就会有8个线程同时访问,失去了锁的作用
             * 本地锁只能锁住当前进程,不能锁住其他服务
             *
             */
            //TODO 本地锁(当前进程锁)synchronized 、 (JUC)Lock  ,分布式情况下必须使用分布式锁
            //下一个线程拿到锁之后先查缓存,缓存中没有再查数据库,避免频繁查库
            String categoryJson = stringRedisTemplate.opsForValue().get("categoryJson");
            if (StringUtils.isNotBlank(categoryJson)){
                Map<String, List<CategoryLevel2Vo>> object = JSON.parseObject(categoryJson, new TypeReference<Map<String, List<CategoryLevel2Vo>>>() {});
                return object;
            }
            System.out.println("当前进程锁查询了数据库");
            List<CategoryEntity> categoryGetAll = baseMapper.selectList(null);
            //一级分类
            List<CategoryEntity> category1Level = getParentCid(categoryGetAll,0L);
            Map<String, List<CategoryLevel2Vo>> collect = category1Level.stream().collect(Collectors.toMap(item -> item.getCatId().toString()
                    , l1 -> {
                        //二级分类
                        List<CategoryEntity> category2Level = getParentCid(categoryGetAll,l1.getCatId());
                        List<CategoryLevel2Vo> collect2 = null;
                        if (category2Level != null){
                            collect2 = category2Level.stream().map(l2 -> {
                                //三级分类
                                List<CategoryEntity> category3Level = getParentCid(categoryGetAll,l2.getCatId());
                                List<CategoryLevel2Vo.CategoryLevel3Vo> collect3 = null;
                                if (category3Level != null){
                                    collect3 = category3Level.stream().map(level3 -> {
                                        return new CategoryLevel2Vo.CategoryLevel3Vo(l2.getCatId().toString(),level3.getCatId().toString(),level3.getName());
                                    }).collect(Collectors.toList());
                                }
                                return new CategoryLevel2Vo(l1.getCatId().toString(),collect3,l2.getCatId().toString(),l2.getName());
                            }).collect(Collectors.toList());
                        }
                        return collect2;

                    }));

            /**
             * 为什么将存入redis放在释放锁之前?
             * 线程拿到锁会去查缓存是否有数据,又因为我们向redis存入缓存数据是在释放锁之后
             * 那么释放锁之后,下一个线程查缓存,上一个线程并未存入完成。此时就会出现查询多次数据库的情况,锁失效
             * 故,存缓存数据应在锁释放之前完成
             */
            //存入缓存redis
            String s = JSON.toJSONString(collect);
            stringRedisTemplate.opsForValue().set("categoryJson",s,1, TimeUnit.DAYS);

            return collect;

        }

    }

测试结果
情况redis缓存,再次测试

缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
缓存未命中,查数据库
当前进程锁查询了数据库
2023-06-04 00:15:55.335  INFO 20204 --- [o-10001-exec-84] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2023-06-04 00:15:55.489  INFO 20204 --- [o-10001-exec-84] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-06-04 00:15:55.495 DEBUG 20204 --- [o-10001-exec-84] c.a.g.p.dao.CategoryDao.selectList       : ==>  Preparing: SELECT cat_id,name,parent_cid,cat_level,show_status,sort,icon,product_unit,product_count FROM pms_category WHERE show_status=1 
2023-06-04 00:15:55.506 DEBUG 20204 --- [o-10001-exec-84] c.a.g.p.dao.CategoryDao.selectList       : ==> Parameters: 
2023-06-04 00:15:55.528 DEBUG 20204 --- [o-10001-exec-84] c.a.g.p.dao.CategoryDao.selectList       : <==      Total: 1425
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回
缓存命中,直接返回

测试成功,只打印了一次“当前进程锁查询了数据库”
在这里插入图片描述
单体服务本地锁测试成功,如果是分布式服务使用单体锁synchronized,那么多少服务实例就会有多少进程,虽然体量不大,但是未达到加锁的目的,为了能更好的解决缓存击穿问题,分布式情况下就不能使用单体进程锁了,必须使用分布式锁
在这里插入图片描述
分布式模拟测试,这里同时启动4个服务,执行线程数100,循环五次
在这里插入图片描述

在这里插入图片描述
测试结果:
只有第一个服务查询了一个数据库,其他服务未查询数据库,这里测试成功的原因可能是并发量不大

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/606557.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java学习方式分享

哈喽&#xff0c;大家好呀&#xff0c;好久不见&#xff01;咱依然是那个腼腆害羞内向社恐文静、唱跳rap篮球都不大行的【三婶er】 坦白地说&#xff0c;今天是偶然看到C站这个活动的&#xff0c;这个主题我颇有感触&#xff0c;刚学java时的场景&#xff0c;历历在目。所以今天…

ChatGPT常见的报错解决方法(全网最全解决方法)

因为最近在使用ChatGPT的过程中&#xff0c;时常会出现一些错误提示&#xff0c;为了方便自己快速解决问题&#xff0c;所以也搜集了一些其他博主的解决方法&#xff0c;以下是整理的内容。 目录 1、拒绝访问 2、Access denied错误 3、We have detected suspicious 错误 4…

leetcode_19_相同的树

bool isSameTree(struct TreeNode* p, struct TreeNode* q){if(pNULL && qNULL)return true;//其中一个为空if(pNULL || qNULL)return false;//都不为空,且首节点的值不相等if(p->val ! q->val)return false;//p和q的值相等&#xff0c;分别比较左子树和右子树re…

如何使用debugHunter发现隐藏调试参数和Web应用程序敏感信息

关于debugHunter debugHunter是一款针对Web应用程序隐藏调试参数和敏感信息的识别扫描工具,该工具本质上是一个Chrome扩展,可以帮助广大研究人员扫描目标Web应用程序/网站以查找调试参数,并在发现了包含修改响应的URL时发送通知。该扩展利用了二分查找算法来有效地确定导致…

《基于Linux物联网综合项目》常见问题汇总fae

关于该课程说明 1&#xff09;本课程目标 通过web浏览器访问服务器&#xff0c;实现登录、注册、数据库操作、远程操控硬件、采集环境信息、远程监控、拍照、图片显示等功能。 将单片机、linux、html、摄像头、数据库等知识点融入到一个项目中。 2&#xff09;什么群体适合学…

JVM 虚拟机栈介绍

一、虚拟机栈&#xff08;VM Stack&#xff09; 1.1&#xff09;什么是虚拟机栈 虚拟机栈是用于描述java方法执行的内存模型。 每个java方法在执行时&#xff0c;会创建一个“栈帧&#xff08;stack frame&#xff09;”&#xff0c;栈帧的结构分为“局部变量表、操作数栈、动态…

JavaScript实现以数组方式输入数值,输出最大的数的代码

以下为实现以数组方式输入数值&#xff0c;输出最大的数的程序代码和运行截图 目录 前言 一、以数组方式输入数值&#xff0c;输出最大的数 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找…

基于html+css的图展示107

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

职业规划-论软件迭代变化和个人知识更新

职业规划-论软件迭代变化和个人知识更新 目录概述需求&#xff1a; 设计思路实现思路分析1.历程2.第一份工作3.后来4.BK毕业5.实习 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardnes…

冈萨雷斯DIP第6章知识点

6.1 彩色基础 区分不同颜色的特性&#xff1f; 区分不同颜色的特性通常是亮度、色调和饱和度。 亮度&#xff1a;亮度体现的是发光强度的消色概念&#xff08;不包含颜色的概念&#xff09;色调&#xff1a;表示被观察者感知的主导色&#xff0c;通常是混合光波中与主波长相关的…

深入理解设计原则之里氏替换原则(LSP)【软件架构设计】

系列文章目录 C高性能优化编程系列 深入理解软件架构设计系列 深入理解设计模式系列 高级C并发线程编程 LSP&#xff1a;里氏替换原则 系列文章目录1、里氏替换原则的定义和解读2、里氏替换原则可以用于哪些设计模式中&#xff1f;3、如何使用里氏替换原则来降低代码耦合度&a…

《微服务架构设计模式》第一章 逃离单体地狱

内容总结自《微服务架构设计模式》 逃离单体地狱 一、单体架构1、好处2、弊端 二、微服务架构1、定义2、好处3、弊端 三、模式的概念1、定义2、构成3、引申微服务 一、单体架构 1、好处 易于对应用程序进行大规模的更改&#xff1a;可以更改代码和数据库模式&#xff0c;然后…

华为OD机试真题 Java 实现【单词倒序】【2023Q1 100分】,附详细解题思路

一、题目描述 输入单行英文句子&#xff0c;里面包含英文字母&#xff0c;空格以及.? 三种标点符号&#xff0c;请将句子内每个单词进行倒序&#xff0c;并输出倒序后的语句。 二、输入描述 输入字符串S&#xff0c;S的长度1≤N≤100。 三、输出描述 输出逆序后的字符串 …

有道云笔记也挺速度,也搞了个AI助手,能抗衡Notion AI?

前言 小编平时做技术笔记的时候&#xff0c;经常使用到的软件就是有道云笔记&#xff0c;最近无意间发现&#xff0c;笔记编写的页面中&#xff0c;竟然集成了AI助手&#xff01;网易有道可真是低调&#xff01;毕竟最近AI圈大火&#xff0c;竟然没有蹭一波热度&#xff0c;直…

Spring Security 核心解读(二)自定义认证授权体系

自定义认证授权体系 概述自定义认证定义登录接口配置 Security 放行策略定义通用登录过滤器并将其配置到 Security 过滤器链上定义资源接口在 Security 授权设置中放行启动项目 结尾 概述 以前使用Spring Security 时&#xff0c;基本都是按部就班参考文档开发。 基本是从 Use…

【Python开发】FastAPI 06:处理错误

某些情况下&#xff0c;有必要向客户端&#xff08;包括前端浏览器、其他应用程序、物联网设备等&#xff09;返回错误提示&#xff0c;以便客户端能够了解错误的类型&#xff0c;从而做出应对。 目录 1 默认处理 1.1 错误介绍 1.2 使用 HTTPException 2 自定义处理 2.1 自…

论旅行之收获2

论旅行之收获2 概况站点第一站&#xff1a;北京市大兴区大兴机场基本情况吐槽小小趣事 第二站&#xff1a;云南省昆明长水机场云南省昆明市五华区基本概况经济分析 第三站&#xff1a;昆明站大理站云南省大理白族自治州大理市下关基本情况 第四站&#xff1a;云南省大理白族自治…

操作系统-进程和线程-处理机调度

目录 一、调度的概念 1.1调度的层次 1.1.1高级调度(作业调度) 1.1.2中级调度(内存调度) 1.1.3低级调度(进程调度) 1.2状态模型 1.3调度的时机 1.4调度方式 1.5进程的切换与过程 二、调度算法的评价指标 2.1CPU利用率 2.2吞吐量 2.3周转时间 2.4带权周转时间 2.5等…

Ansible基础6——文件模块、jinja2模板

文章目录 一、常用文件模块1.1 blockinfile模块1.2 file模块1.2.1 创建文件并赋予权限1.2.2 创建目录并赋予权限1.2.3 创建软连接1.2.4 删除文件或目录 1.3 fetch模块1.4 lineinfile模块1.5 stat模块1.6 synchronize模块 二、jinja2模板2.1 构建jinja2模板2.2 管理jinja2模板2.…

LVGL学习(1):中文字体的转换和汉字显示

在使用LVGL的过程中&#xff0c;我们难免需要显示汉字&#xff0c;所以这篇文章就来介绍一下如何转换中文汉字并成功显示到LVGL中。 文章目录 1 字体转换1.1 GUI Guider自动转换1.2 在线转换 2 字体的使用 1 字体转换 1.1 GUI Guider自动转换 打开GUI Guide&#xff0c;创建…