当前位置: 首页 > news >正文

Redis学习从入门到掌握(基础篇)

文章目录

  • 一、初识Redis
    • 1.认识 Redis
    • 2.Redis常见命令
      • (1)Redis 数据结构介绍
      • (2)Redis 通用命令
      • (3)String 类型
      • (4)String 类型的常见命令
      • (5)Hash 类型
      • (6)Hash 类型的常见命令
      • (7)List 类型
      • (8)List 类型的常见命令
      • (9)Set 类型
      • (10)Set 类型的常见命令
      • (11)SortedSet 类型
      • (12)SortedSet 类型的常见命令
    • 3.Redis 的 Java 客户端
      • (1)Jedis
      • (2)Jedis 连接池
      • (3)SpringDataRedis
      • (4)SpringDataRedis 快速入门
      • (5)SpringDataRedis 的序列化方式

一、初识Redis

1.认识 Redis

认识Redis
Redis 诞生于2009年全称是Remote Dictionary Server ,远程词典服务器,是一个基于内存的键值型NoSQL 数据库。
特征:

  • 键值(key-value )型,value 支持多种不同数据结构,功能丰富

  • 单线程,每个命令具备原子性

  • 低延迟,速度快(基于内存、10多路复用、良好的编码)。

  • 支持数据持久化

  • 支持主从集群、分片集群

  • 支持多语言客户端

2.Redis常见命令

(1)Redis 数据结构介绍

  • Redis 是一个key-value 的数据库,key一般是String 类型,不过value 的类型多种多样
  • String
  • Hash
  • List
  • Set
  • Sortedset(Zset)
  • GEO
  • BitMap
  • HyperLog

(2)Redis 通用命令

通用指令是部分数据类型的,都可以使用的指令,常见的有:

  • KEYS:查看符合模板的所有key
  • DEL:删除一个指定的key
  • EXISTS :判断key是否存在
  • EXPIRE :给一个key设置有效期,有效期到期时该key会被自动删除
  • TTL:查看一个KEY的剩余有效期

(3)String 类型

String 类型,也就是字符串类型,是Redis 中最简单的存储类型。
其value 是字符串,不过根据字符串的格式不同,又可以分为3类:

  • string :普通字符串
  • int:整数类型,可以做自增、自减操作
  • float :浮点类型,可以做自增、自减操作

不管是哪种格式,底层都是字节数组形式存储,只不过是编码方式不同。字符串类型的最大空间不能超过512m。

(4)String 类型的常见命令

  • SET :添加或者修改已经存在的一个 String 类型的键值对。

  • GET :根据 key 获取 String 类型的 value。
    请添加图片描述

  • MSET :批量添加多个 String 类型的键值对。

  • MGET :根据多个 key 获取多个 String 类型的 value。
    请添加图片描述

  • INCR :让一个整型的 key 自增 1。

  • INCRBY: 让一个整型的 key 自增并指定步长,例如: incrby num 2 让 num 值自增 2。

  • INCRBYFLOAT :让一个浮点类型的数字自增并指定步长。
    请添加图片描述

  • SETNX :添加一个 String 类型的键值对,前提是这个 key 不存在,否则不执行。
    请添加图片描述

  • SETEX :添加一个 String 类型的键值对,并且指定有效期。
    请添加图片描述

(5)Hash 类型

Hash类型,也叫散列,其value 是一个无序字典,类似于Java中的HashMap 结构。
String 结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便:

hotel:user:1{name:“Jack”, age:21}
hotel:user:2{name:“Rose”, age:18}

Hash 结构可以将对象中的每个字段独立存储,可以针对单个字段做 CRUD :

KEYfieldvalue
hotel:user:1namejack
age21
hotel:user:2nameRose
age18

(6)Hash 类型的常见命令

  • HSET key field value :添加或者修改 hash 类型 key 的 field 的值。

  • HGET key field :获取一个 hash 类型 key 的 field 的值
    请添加图片描述

  • HMSET :批量添加多个 hash 类型 key 的 field 的值

  • HMGET :批量获取多个 hash 类型 key 的 field 的值

  • HGETALL :获取一个 hash 类型的 key 中的所有的 field 和 value
    请添加图片描述

  • HKEYS :获取一个 hash 类型的 key 中的所有的 field

  • HVALS :获取一个 hash 类型的 key 中的所有的 value
    请添加图片描述

  • HINCRBY: 让一个 hash 类型 key 的字段值自增并指定步长

  • HSETNX :添加一个 hash 类型的 key 的 field 值,前提是这个 field 不存在,否则不执行
    请添加图片描述

(7)List 类型

Redis 中的List类型与Java中的LinkedList 类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。
特征也与LinkedList 类似:

  • 有序
  • 元素可以重复
  • 插入和删除快
  • 查询速度一般

常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。

(8)List 类型的常见命令

  • LPUSH key element … :向列表左侧插入一个或多个元素
  • LPOP key :移除并返回列表左侧的第一个元素,没有则返回 nil
  • RPUSH key element … :向列表右侧插入一个或多个元素
  • RPOP key :移除并返回列表右侧的第一个元素
  • LRANGE key star end :返回一段角标范围内的所有元素
  • BLPOP 和 BRPOP :与 LPOP 和 RPOP 类似,只不过在没有元素时等待指定时间,而不是直接返回 nil
    请添加图片描述

请添加图片描述

(9)Set 类型

Redis 的Set结构与Java中的HashSet 类似,可以看做是一个value 为null的HashMap 。因为也是一个hash表,因此具备与HashSet 类似的特征:

  • 无序
  • 元素不可重复
  • 查找快
  • 支持交集、并集、差集等功能
    请添加图片描述

(10)Set 类型的常见命令

  • SADD key member … :向 set 中添加一个或多个元素

  • SREM key member … : 移除 set 中的指定元素

  • SCARD key : 返回 set 中元素的个数

  • SISMEMBER key member :判断一个元素是否存在于 set 中
    请添加图片描述

  • SMEMBERS :获取 set 中的所有元素

  • SINTER key1 key2 … :求 key1 与 key2 的交集
    请添加图片描述

  • SDIFF key1 key2 … :求 key1 与 key2 的差集

  • SUNION key1 key2 … :求 key1 和 key2 的并集
    请添加图片描述

(11)SortedSet 类型

Redis 的Sortedset 是一个可排序的set集合,与java中的TreeSet 有些类似,但底层数据结构却差别很大。Sortedset 中的每一个元素都带有一个score 属性,可以基于score 属性对元素排序,底层的实现是一个跳表(SkipList )加hash表。
SortedSet 具备下列特性:

  • 可排序
  • 元素不重复
  • 查询速度快

因为SortedSet 的可排序特性,经常被用来实现排行榜这样的功能。

(12)SortedSet 类型的常见命令

ZADD key score member :添加一个或多个元素到 sorted set ,如果已经存在则更新其 score 值

  • ZREM key member :删除 sorted set 中的一个指定元素
  • ZSCORE key member : 获取 sorted set 中的指定元素的 score 值
  • ZRANK key member :获取 sorted set 中的指定元素的排名
  • ZCARD key :获取 sorted set 中的元素个数
  • ZCOUNT key min max :统计 score 值在给定范围内的所有元素的个数
  • ZINCRBY key increment member :让 sorted set 中的指定元素自增,步长为指定的 increment 值
  • ZRANGE key min max :按照 score 排序后,获取指定排名范围内的元素
  • ZRANGEBYSCORE key min max :按照 score 排序后,获取指定 score 范围内的元素
    请添加图片描述
  • ZDIFF 、 ZINTER 、 ZUNION :求差集、交集、并集

注意:所有的排名默认都是升序,如果要降序则在命令的 Z 后面添加 REV 即可

3.Redis 的 Java 客户端

在 Redis 官网中提供了各种语言的客户端,地址: https://redis.io/clients

(1)Jedis

jedis官网https://github.com/redis/jedis

  • 引入依赖:
        <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version></dependency>
  • 创建 Jedis 对象,建立连接:
    public Jedis setUp() {//建立连接Jedis jedis = new Jedis("127.0.0.1", 6379);//选择库jedis.select(0);return jedis;}
  • 使用 Jedis ,方法名与 Redis 命令一致:
@Testpublic void testString() {Jedis jedis = setUp();try {//插入数据,方法名称就是 redis命令名称,非常简单String result = jedis.set("name", " 张三 ");System.out.println("result = " + result);//获取数据String name = jedis.get("name");System.out.println("name = " + name);} finally {jedis.close();}}

(2)Jedis 连接池

Jedis 本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis 连接池代替Jedis 的直连。

    private static final JedisPool jedisPool;static {JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();//最大连接jedisPoolConfig.setMaxTotal(8);//最大空闲连接jedisPoolConfig.setMaxIdle(8);//最小空闲连接jedisPoolConfig.setMinIdle(0);//设置最长等待时间, msjedisPoolConfig.setMaxWaitMillis(200);jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379,1000);}//获取 Jedis对象public static Jedis getJedis() {return jedisPool.getResource();}

(3)SpringDataRedis

SpringData 是Spring 中数据操作的模块,包含对各种数据库的集成,
其中对Redis 的集成模块就叫做Spring DataRedis ,官网地址:https://spring.io/projects/spring-data-redis/
提供了对不同 Redis 客户端的整合( Lettuce 和 Jedis )

  • 提供了 RedisTemplate 统一 API 来操作 Redis
  • 支持 Redis 的发布订阅模型
  • 支持 Redis 哨兵和 Redis 集群
  • 支持基于 Lettuce 的响应式编程
  • 支持基于 JDK 、 JSON 、字符串、 Spring 对象的数据序列化及反序列化
  • 支持基于 Redis 的 JDKCollection 实现

(4)SpringDataRedis 快速入门

SpringDataRedis 中提供了 RedisTemplate 工具类,其中封装了各种对 Redis 的操作。并且将不同数据类型的操作
API 封装到了不同的类型中:
请添加图片描述

  • 引入依赖:
		<!--Redis依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--连接池依赖 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>
  • 配置文件:
spring:redis:host: 127.0.0.1port: 6379lettuce:pool:max-active: 8     #最大连接max-idle: 8       #最大空闲连接min-idle: 0       #最小空闲连接max-wait: 100     #连接等待时间
  • 编写测试
	@Autowiredprivate RedisTemplate redisTemplate;@Testpublic void testString() {//插入一条 string类型数据redisTemplate.opsForValue().set("name", " 李四 ");//读取一条 string类型数据Object name = redisTemplate.opsForValue().get("name");System.out.println("name = " + name);}

(5)SpringDataRedis 的序列化方式

RedisTemplate 可以接收任意 Object 作为值写入 Redis ,只不过写入前会把 Object 序列化为字节形式,默认是采用 JDK 序列化,得到的结果是这样的:
请添加图片描述
缺点:

  • 可读性差
  • 内存占用较大

我们可以自定义 RedisTemplate 的序列化方式,代码如下:

    @Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {//创建 TemplateRedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();//设置连接工厂redisTemplate.setConnectionFactory(redisConnectionFactory);//设置序列化工具GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();// key和 hashKey采用 string序列化redisTemplate.setKeySerializer(RedisSerializer.string());redisTemplate.setHashKeySerializer(RedisSerializer.string());// value和 hashValue采用 JSON序列化redisTemplate.setValueSerializer(jsonRedisSerializer);redisTemplate.setHashValueSerializer(jsonRedisSerializer);return redisTemplate;}

尽管 JSON 的序列化方式可以满足我们的需求,但依然存在一些问题,如图:
请添加图片描述

为了在反序列化时知道对象的类型, JSON 序列化器会将类的 class 类型写入 json 结果中,存入 Redis ,会带来额外的内存开销。

为了节省内存空间,我们并不会使用 JSON 序列化器来处理 value ,而是统一使用 String 序列化器,要求只能存储String 类型的 key 和 value 。当需要存储 Java 对象时,手动完成对象的序列化和反序列化。

Spring 默认提供了一个 StringRedisTemplate 类,它的 key 和 value 的序列化方式默认就是 String 方式。省去了我们自定义 RedisTemplate 的过程:

	@Autowired(required = false)private StringRedisTemplate stringRedisTemplate;// JSON工具private static final ObjectMapper mapper = new ObjectMapper();@Testpublic void testStringTemplate() throws JsonProcessingException {//准备对象User user = new User(" 虎哥 ", 18);//手动序列化String json = mapper.writeValueAsString(user);//写入一条数据到 redisstringRedisTemplate.opsForValue().set("user:200", json);//读取数据String val = stringRedisTemplate.opsForValue().get("user:200");//反序列化User user1 = mapper.readValue(val, User.class);System.out.println("user1 = " + user1);}

相关文章:

Redis学习从入门到掌握(基础篇)

文章目录 一、初识Redis1.认识 Redis2.Redis常见命令&#xff08;1&#xff09;Redis 数据结构介绍&#xff08;2&#xff09;Redis 通用命令&#xff08;3&#xff09;String 类型&#xff08;4&#xff09;String 类型的常见命令&#xff08;5&#xff09;Hash 类型&#xff…...

redis主从复制、哨兵

目录 1. 主从复制 特点&#xff1a; 工作原理&#xff1a; 配置&#xff1a; 2. 哨兵 特点&#xff1a; 工作原理&#xff1a; 配置&#xff1a; ​编辑 1. 主从复制 特点&#xff1a; 主从复制是 Redis 最基本的高可用性方案。主节点&#xff08;Master&#xff09…...

uniapp登录拦截白名单使用

1、创建uni.promisify.adaptor.js文件 // 根目录新建 uni.promisify.adaptor.js // 路由白名单 const list [/, /pages/stroke/stroke]; //创建路由拦截&#xff0c;这里只判断一般跳转 uni.addInterceptor(switchTab, {invoke(res) {console.log(res);//存在token就跳转if (…...

力扣45. 跳跃游戏 II

Problem: 45. 跳跃游戏 II 文章目录 题目描述思路复杂度Code 题目描述 思路 1.获取数组的长度len&#xff0c;定义int类型变量end用于标记每次在当前可以跳到的最远距离&#xff0c;farthest用于记录每次可以跳跃到的最远距离&#xff0c;jumps用于记录最小的跳跃次数&#xff…...

MXNet安装:专业指南与深度解析

一、引言 MXNet是一个高效且灵活的深度学习框架&#xff0c;它支持多种编程语言和平台&#xff0c;并提供了丰富的深度学习算法和工具。随着深度学习技术的广泛应用&#xff0c;MXNet因其出色的性能和易用性受到了越来越多开发者和研究人员的青睐。本文将详细介绍MXNet的安装过…...

C++函数模板案例--数组封装

目录 一、数组封装的需求 案例描述: 二、实操 创建.hpp文件&#xff0c;编写数组类。 浅拷贝危害 拷贝构造函数 “”重载 尾插法 尾删法 “[]"重载 返回数组容量、大小 完整代码 编写.cpp文件&#xff0c;对自定义数组进行测试。 打印数组函数 test01测试函数…...

传统文字检测方法+代码实现

文章目录 前言传统文字检测方法1、基于最大稳定极值区域&#xff08;MSER&#xff09;的文字检测1.1 MSER&#xff08;MSER-Maximally Stable Extremal Regions&#xff09;基本原理代码实现——使用Opencv中的cv2.MSER_create()接口 2、基于笔画宽度变换&#xff08;Stroke Wi…...

Jmeter从数据为查找结果集数据方法随笔

一、Jmeter连接数据库 1.下载对应数据库的驱动包到jmeter安装目录的lib下ext文件中&#xff0c;并导入到jmeter的测试计划中&#xff0c;本实例中使用的是mysql如下所示&#xff1a; 点击测试计划–>点击浏览–>选中mysql驱动jar包–>打开 2.添加线程组&#xff0c;…...

Objective-C网络请求开发的高效实现方法与技巧

前言 在移动应用开发中&#xff0c;网络请求是一项至关重要的技术。Objective-C作为iOS平台的主要开发语言之一&#xff0c;拥有丰富的网络请求开发工具和技术。本文将介绍如何利用Objective-C语言实现高效的网络请求&#xff0c;以及一些实用的技巧和方法。 1.Objective-C技…...

Java:OOP之术语或概念

■■ 编程和程序设计 ■□ 程序员和编程■ 程序员&#xff1a;programmer■ 编程&#xff1a;program, programming■ 面向过程&#xff1a;Process oriented■ 面向对象&#xff1a;object-oriented● 面向对象分析&#xff1a;OOA&#xff0c;全称Object-oriented Analysis●…...

内存地产风云录:malloc、free、calloc、realloc演绎动态内存世界的楼盘开发与交易大戏

欢迎来到白刘的领域 Miracle_86.-CSDN博客 系列专栏 C语言知识 先赞后看&#xff0c;已成习惯 创作不易&#xff0c;多多支持&#xff01; 在这个波澜壮阔的内存地产世界中&#xff0c;malloc、free、calloc和realloc四位主角&#xff0c;共同演绎着一场场精彩绝伦的楼盘开…...

个人博客项目笔记_05

1. ThreadLocal内存泄漏 ThreadLocal 内存泄漏是指由于没有及时清理 ThreadLocal 实例所存储的数据&#xff0c;导致这些数据在线程池或长时间运行的应用中累积过多&#xff0c;最终导致内存占用过高的情况。 内存泄漏通常发生在以下情况下&#xff1a; 线程池场景下的 ThreadL…...

基础知识点全覆盖(1)

Python基础知识点 1.基本语句 1.注释 方便阅读和调试代码注释的方法有行注释和块注释 1.行注释 行注释以 **# **开头 # 这是单行注释2.块注释 块注释以多个 #、三单引号或三双引号(注意: 基于英文输入状态下的标点符号) # 类 # 似 # 于 # 多 # 行 # 效 # 果 这就是多行注释…...

异常处理java

在Java中&#xff0c;异常处理可以使用"throws"关键字或者"try-catch"语句。这两种方法有不同的用途和适用场景。 "throws"关键字: 在方法声明中使用"throws"关键字&#xff0c;表示该方法可能会抛出异常&#xff0c;但是并不立即处理…...

个人博客项目_09

1. 归档文章列表 1.1 接口说明 接口url&#xff1a;/articles 请求方式&#xff1a;POST 请求参数&#xff1a; 参数名称参数类型说明yearstring年monthstring月 返回数据&#xff1a; {"success": true, "code": 200, "msg": "succ…...

【2024年MathorCup数模竞赛】C题赛题与解题思路

2024年MathorCup数模竞赛C题 题目 物流网络分拣中心货量预测及人员排班背景求解问题 解题思路问题一问题二问题三问题四 本次竞赛的C题是对物流网络分拣中心的货量预测及人员排班问题进行规划。整个问题可以分为两个部分&#xff0c;一是对时间序列进行预测&#xff0c;二是对人…...

蓝桥杯省赛冲刺(3)广度优先搜索

广度优先搜索&#xff08;Breadth-First Search, BFS&#xff09;是一种在图或树等非线性数据结构中遍历节点的算法&#xff0c;它从起始节点开始&#xff0c;按层级逐步向外扩展&#xff0c;即先访问离起始节点最近的节点&#xff0c;再访问这些节点的邻居&#xff0c;然后是邻…...

网页内容生成图片,这18般武艺你会几种呢?

前言 关于【SSD系列】&#xff1a; 前端一些有意思的内容&#xff0c;旨在3-10分钟里&#xff0c; 500-1000字&#xff0c;有所获&#xff0c;又不为所累。 网页截图&#xff0c;windows内置了快捷命令和软件&#xff0c;chrome开发者工具也能一键截图&#xff0c;html2canva…...

pytest的时候输出一个F后面跟很多绿色的点解读

使用pytest来测试pyramid和kotti项目&#xff0c;在kotti项目测试的时候&#xff0c;输出一个F后面跟很多绿色的点&#xff0c;是什么意思呢&#xff1f; 原来在使用pytest进行测试时&#xff0c;输出中的“F”代表一个失败的测试&#xff08;Failed&#xff09;&#xff0c;而…...

算法打卡day33

今日任务&#xff1a; 1&#xff09;509. 斐波那契数 2&#xff09;70. 爬楼梯 3&#xff09;746.使用最小花费爬楼梯 509. 斐波那契数 题目链接&#xff1a;509. 斐波那契数 - 力扣&#xff08;LeetCode&#xff09; 斐波那契数&#xff0c;通常用 F(n) 表示&#xff0c;形成…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...