yx的学习日记

1:算是正式开始把。。。。。

还是看了一下redis的视频,今天主要学习的是redis的客户端,在下面总结,然后具体学习了一下算法的时间复杂度分析。。

2:JAVA

Redis客户端的学习

Redis客户端到底是个啥呢?简单来说,它就像是一个"接口",只不过这个接口的具体实现是由各种编程语言提供的。我们主要关注的是Java里的两个常用工具:`Jedis`和`Spring-Redis`。通过它们,Java可以提供一些类和方法,用来创建连接、操作Redis数据库。大体流程是:先建立连接,然后通过Redis对象来操作数据。 接下来,我具体讲一下`Jedis`和`Spring-Redis`的区别,以及我是怎么学习它们的。


Jedis

首先看`Jedis`,它的使用其实很简单。比如,我们可以这样写代码来连接Redis:

csharp 复制代码
private Jedis jedis;
@BeforeEach
void setUp() {
    // 设置Redis的地址和端口号
    jedis = new Jedis("192.168.100.128", 6379);
    // 设置密码
    jedis.auth("123");
    // 选择数据库(Redis支持多个库,默认是0号库)
    jedis.select(0);
}

这里的Jedis连接配置,其实就是告诉程序:你要连哪个Redis服务器(远程还是本地)、用什么端口、密码是多少,以及选哪个数据库。如果是本地连接,区别就在于主机地址(host)不同。


Jedis操作Redis的例子

接下来看几个实际操作Redis的例子。 **1. 操作字符串** 比如,我们可以用`set`和`get`方法来存取数据:

csharp 复制代码
void testString() {
    String result = jedis.set("name", "zzh"); // 存入键值对
    System.out.println("result=" + result);   // 打印结果
    String name = jedis.get("name");         // 获取键对应的值
    System.out.println("name=" + name);      // 打印值
}

这里,jedis.set就相当于在Redis命令行里执行SET name zzh,而jedis.get就是GET name。本质上,Jedis就是把命令行的操作封装成了代码。 2. 操作哈希表 再比如,我们可以用hsethgetall来操作哈希表:

javascript 复制代码
void testHash() {
    // 插入哈希表数据
    jedis.hset("user:1", "name", "张智昊");
    jedis.hset("user:1", "age", "18");
    // 获取整个哈希表
    Map<String, String> hgetAll = jedis.hgetAll("user:1");
    System.out.println(hgetAll); // 打印结果
}

运行后,你会看到类似这样的输出:

ini 复制代码
{name=张智昊, age=18}

Jedis的局限性

虽然`Jedis`用起来挺方便,但它也有点麻烦的地方。比如,它的方法参数要求很严格,必须是固定的格式。我们来看一下源码:

kotlin 复制代码
public String set(String key, String value) {
    this.checkIsInMultiOrPipeline();
    this.client.set(key, value);
    return this.client.getStatusCodeReply();
}
public String set(String key, String value, SetParams params) {
    this.checkIsInMultiOrPipeline();
    this.client.set(key, value, params);
    return this.client.getStatusCodeReply();
}

从源码可以看出,set方法只能接受keyvalue都是字符串类型的参数。如果你想插入类似user:{"name":"zzh"}这种结构化的数据,Jedis是不支持的,得自己想办法绕过去。 同理,get方法也要求传入的key必须是字符串类型:

kotlin 复制代码
public String get(String key) {
    this.checkIsInMultiOrPipeline();
    this.client.get(key);
    return this.client.getBulkReply();
}

总结一下,Jedis的用法其实跟直接在Redis命令行里敲命令差不多,但因为它的参数限制比较死板,所以有时候会显得有点麻烦。


总结

总的来说,`Jedis`就是一个能让我们用Java代码操作Redis的工具。它的好处是简单直接,缺点是灵活性不够,尤其是处理复杂数据结构时会有点别扭。至于`Spring-Redis`,它在`Jedis`的基础上做了更多封装,后面我会继续学习并分享心得。


spring-redis:

我们先来看一下 `spring-redis` 是如何使用的。以下是一个简单的代码示例,展示了如何通过 `RedisTemplate` 操作 Redis 中的字符串类型数据:

csharp 复制代码
void TestString() {
    // 使用 opsForValue() 方法设置键值对
    redisTemplate.opsForValue().set("name:", "张智昊");
    
    // 通过键获取对应的值
    Object name = redisTemplate.opsForValue().get("name:");
    
    // 输出获取到的值
    System.out.println("name=" + name);
}

从这段代码中可以看出,Spring 框架内置了一个名为 StringRedisTemplate 的工具类,其中提供了 opsForValue() 方法。通过这个方法,我们可以选择操作 Redis 中的数据类型。例如,上面的代码演示了如何对字符串类型的数据进行存储和获取(键值对形式)。

默认序列化机制的问题

然而,默认情况下,`RedisTemplate` 使用的是 Spring 自带的序列化机制(通常是基于 Java 的序列化方式)。这种序列化方式会将数据以二进制的形式存储到 Redis 中。例如,当我们插入键值对 `"name:" -> "张智昊"` 时,实际存储到 Redis 中的数据可能如下所示:

复制代码
\xac\xed\x00\x05t\x00\x09\xe5\xbc\xa0\xe6\x99\xba\xe6\x98\x8a

可以看到,这段数据是经过序列化后的二进制内容,虽然它能够被程序正确解析,但对于人类来说几乎是不可读的。这种默认的序列化机制可能会带来以下几个问题:

  1. 可读性差:由于数据是以二进制形式存储的,直接查看 Redis 数据库的内容时无法直观理解其含义。
  2. 兼容性问题:如果其他语言或框架需要与 Redis 进行交互,它们可能无法解析这种特定的序列化格式。
  3. 调试困难:在开发和调试过程中,查看 Redis 数据变得复杂,增加了排查问题的难度。
解决方案:自定义序列化机制

为了解决上述问题,我们可以通过自定义 `RedisTemplate` 的序列化器来改进数据存储的方式。例如,可以使用 `StringRedisSerializer` 或 `Jackson2JsonRedisSerializer` 等更友好的序列化方式,使存储的数据更加清晰易读。 以下是配置 `RedisTemplate` 使用 `StringRedisSerializer` 的示例代码:

arduino 复制代码
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    
    // 设置 key 和 value 的序列化器
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(new StringRedisSerializer());
    
    // 设置连接工厂
    template.setConnectionFactory(redisConnectionFactory);
    
    return template;
}

通过这种方式,存储到 Redis 中的数据将变为更直观的字符串形式。例如,插入 "name:" -> "张智昊" 后,Redis 中的实际存储内容将直接显示为:

arduino 复制代码
"张智昊"

这不仅提高了数据的可读性,还增强了与其他系统的兼容性,同时也便于开发人员进行调试和维护。

3:数据结构于算法

时间复杂度:

主要是学习了一下时间复杂度分析,这算算法的基础吧,毕竟算法就是如何用更短的时间更小的内存去实现同样的事情

我感觉学到的主要就是你去关注那个带n的式子常数级别的运算,对整个程序影响不大,一旦牵扯到n就提高一个层次:

大 O 复杂度表示法:

**1. 只关注循环执行次数最多的一段代码**

我刚才说了,大 O 这种复杂度表示方法只是表示一种变化趋势。我们通常会忽略掉公式中的常量、低阶、系数,只需要记录一个最大阶的量级就可以了。所以, 我们在分析一个算法、一段代码的时间复杂度的时候,也只关注循环执行次数最多的那一段代码就可以了 。这段核心代码执行次数的 n 的量级,就是整段要分析代码的时间复杂度。

2. 加法法则:总复杂度等于量级最大的那段代码的复杂度

总的时间复杂度 * *等于量级最大的那段代码的时间复杂度。那我们将这个规律抽象成公式就是:

如果 T1(n)=O(f(n)),T2(n)=O(g(n));那么 T(n)=T1(n)+T2(n)=max(O(f(n)), O(g(n))) =O(max(f(n), g(n))).

3. 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

我刚讲了一个复杂度分析中的加法法则,这儿还有一个 乘法法则 。类比一下,你应该能"猜到"公式是什么样子的吧?

如果 T1(n)=O(f(n)),T2(n)=O(g(n));那么 T(n)=T1(n)T2(n)=O(f(n)) O(g(n))=O(f(n)*g(n)).

也就是说,假设 T1(n) = O(n),T2(n) = O(n2),则 T1(n) * T2(n) = O(n3)。

空间复杂度分析

前面,咱们花了很长时间讲大 O 表示法和时间复杂度分析,理解了前面讲的内容,空间复杂度分析方法学起来就非常简单了。

前面我讲过,时间复杂度的全称是 渐进时间复杂度表示算法的执行时间与数据规模之间的增长关系 。类比一下,空间复杂度全称就是 渐进空间复杂度 (asymptotic space complexity), 表示算法的存储空间与数据规模之间的增长关系

我还是拿具体的例子来给你说明。(这段代码有点"傻",一般没人会这么写,我这么写只是为了方便给你解释。)

css 复制代码
void print(int n) {
​
  int i = 0;
​
  int[] a = new int[n];
​
  for (i; i <n; ++i) {
​
    a[i] = i * i;
​
  }
​
 
​
  for (i = n-1; i >= 0; --i) {
​
    print out a[i]
​
  }
​
}
复制代码

跟时间复杂度分析一样,我们可以看到,第 2 行代码中,我们申请了一个空间存储变量 i,但是它是常量阶的,跟数据规模 n 没有关系,所以我们可以忽略。第 3 行申请了一个大小为 n 的 int 类型数组,除此之外,剩下的代码都没有占用更多的空间,所以整段代码的空间复杂度就是 O(n)。

我们常见的空间复杂度就是 O(1)、O(n)、O(n2 ),像 O(logn)、O(nlogn) 这样的对数阶复杂度平时都用不到。而且,空间复杂度分析比时间复杂度分析要简单很多。所以,对于空间复杂度,掌握刚我说的这些内容已经足够了。

相关推荐
林太白7 分钟前
Next.js超简洁完整篇
前端·后端·react.js
前端付豪7 分钟前
汇丰登录风控体系拆解:一次 FaceID 被模拟攻击的调查纪实
前端·后端·架构
无名之逆18 分钟前
大三自学笔记:探索Hyperlane框架的心路历程
java·开发语言·前端·spring boot·后端·rust·编程
yang_xiao_wu_18 分钟前
springboot+mybatis面试题
spring boot·后端·mybatis
Chuck1sn20 分钟前
我把 Cursor AI 整合到 Ruoyi 中,从此让 Java 脚手架脱离人工!
java·vue.js·后端
水木石画室23 分钟前
Spring Boot 常用注解面试题深度解析
java·spring boot·后端
阿杆25 分钟前
想体验出海应用赚钱?试试这个一年免费的香港服务器
后端·产品·创业
汤圆和烟灰儿44 分钟前
Linux 防火墙工具 iptables 入门与常用命令整理
后端
bcbnb44 分钟前
iOS性能调试完整流程实录:工具组合下的问题定位与修复实践(含keymob)
后端
上车函予44 分钟前
干掉图形验证码!基于PoW的Cap验证码集成指南
前端·后端