redis笔记

Redis

1 Redis和mysql客户端和服务端

mysql端口:3306

redis端口:6379

端口号是暴露给外部设备的逻辑端点,告诉外部设备这个端口号对应不同的服务,用于连接服务端通信。

Pid是计算机内部不同进程的唯一标识,用于计算机内部管理区分不同的服务

2 token和cookie的区别

理解二者本质就可以明白了。

  • cookie是一种存储机制,存储在客户端表示用户标号,cookie里面可以存储token,数字等其他形式字符。
  • token是一个随机字符串,可以存在客户端的cookie里,也可以存在服务端的session或者reids里。

二者本质就不一样,cookie是一种存储机制,token是一个字符串。

3.redis的相关配置

3.1 区分timeout和connect-time的区别

image-20250415184931341

4 redis做缓存和cpu缓存区别?

下面这两个介绍了什么是缓存,redis做缓存和cpu的内部缓存区别?

先说结论:cpu是硬件级缓存,redis是软件级缓存,二者没有直接关联,但是都是通过缓存提升访问速度。

理解这个概念要梳理清楚cpu,内存,硬盘之间的关系,cpu缓存和redis缓存的区别。java客户端由服务器,这个服务器上有cpu;redis服务器上也有宿主机的cpu;但是注意,java客户端和reids服务器都是运行在宿主机上的服务程序,他们访问内存中的数据可以从本地宿主机上读取缓存,但是java客户端通过网络传输读取数据一定是从redis服务器的宿主机的内存中进行读取。

image-20250417222844222

参考两个博主解释:

1.[如何快速了解什么是计算机的缓存 - 知乎](https://zhuanlan.zhihu.com/p/19591511172#:~:text=1、 CPU 缓存:位于 CPU 内部的缓存,分为一级缓存(L1)、二级缓存(L2)和三级缓存(L3)。 这些缓存是最接近 CPU,的,因此访问速度最快。 CPU 缓存的作用是暂时存储 CPU 频繁使用的数据,以避免每次都从主内存中获取数据。 2、 内存缓存:在操作系统层面上,内存也可以作为缓存使用。)

2.Redis是如何做缓存的 - 知乎

5 reids基本语法及使用

5.1 五种基本数据类型

image-20250417224547099

5.2 字符串常用命令

image-20250418000052628

5.3 哈希结构常用命令

image-20250418001203129

5.4 集合操作命令

image-20250418003744667

5.5 列表操作命令

image-20250418003811883

5.6 redis通用命令

image-20250418164113585

6 redis使用

6.1 redis使用配置

image-20250418165010883

6.2 redis使用场景——缓存

6.3 redis使用场景——限流

(1)自定义限流注解

注解的属性定义规范

注意两个问题:

  • 注解的属性定义为什么和抽象方法一样?
  • 注解的属性定义怎样定义?

image-20250421193637376

7 redis开发笔记

配合spring_rbac这个项目熟悉。

1.
工具类里面封装的set方法value写成了string,导致我无法存入user类型
//        redisUtil.set("userId" + user.getUserId(), "user{" + user + "}");
不用工具类,用原生的opsForValue的set方法可以存储user实体类类型
//        redisTemplate.opsForValue().set(user.getUserName(), user);

2.
public List<DictData> selectDictDataByType(String dictType) {
        Object dictDataList1 = redisUtil.get(dictType);
        //这个地方注意:要用!=null判断,如果redis里面没有这个键会返回null,这时候再用isEmpty()判断是否是空列表就不行了
        - mybatis返回list用isEmpty判断是否是空列表,mybatis不会返回空,他会返回空列表。
        - redis这里如果键不存在的话,返回的是null,而不是空列表
        if (dictDataList1 != null) {
            System.out.println("这是redis里面存储的数据" + dictDataList1);
            return (List<DictData>) dictDataList1;
        } else {
            List<DictData> dictDataList2 = dictDataMapper.selectDictDataBytype(dictType);
            System.out.println("这是mysql里面存储的数据" + dictDataList2);
            redisTemplate.opsForValue().set(dictType, dictDataList2);
            return dictDataList2;
        }


3.
<insert id="insertDictType" parameterType="DictType">
        insert into tb_dict_type(
        <if test="dictName != null and dictName != ''">dict_name,</if>
        <if test="dictType != null and dictType != ''">dict_type,</if>
        <if test="status != null">status,</if>
        <if test="remark != null and remark != ''">remark,</if>
        <if test="createBy != null and createBy != ''">create_by,</if>
        create_time
        )values(
        <if test="dictName != null and dictName != ''">#{dictName},</if>
        <if test="dictType != null and dictType != ''">#{dictType},</if>
        <if test="status != null">#{status},</if>
        <if test="remark != null and remark != ''">#{remark},</if>
        <if test="createBy != null and createBy != ''">#{createBy},</if>
        sysdate()
        )
    </insert>

 sysdate(),返回数据插入的时间,由数据库服务器生成

4.
看哪个完整系统接口的时候,发现他添加数据时候service层校验逻辑写在了controller层,
经过查找发现,传统的项目,service层的业务逻辑包括了从数据库查出来的校验逻辑,而现在的项目,校验方法还是写在
service层,但是校验逻辑写在了controller层也可以,看你自己了。

5.写了这几个接口,我现在总结一下我书写的命名规范:
(1)crud名字命名上(简单crud,不涉及校验逻辑的情况下):
    - mapper层方法名用:
        - insert
        - delete
        - update
        - select
    - service层和controller层方法名:
        - add/save
        - delete
        - update
        - select
    controller层的请求地址可以省略后缀重点表示crud就可以
(2)如果包含校验逻辑
    controller和mapper层方法命名不变
    -service层变化
        - isAdd (是否添加)
        - isUpdate(是否修改)
        - delete 删除 这个删除注意:(业务表用update逻辑删除,字典表用delete物理删除)
        - select
    校验逻辑一般简单开发就两种:
        - 用javaweb的传统方法:先执行一个selectByid/selectByCondition,查询数据库里面是否有值,然后再根据返回结果添加
        - 用抛出异常,这里分为两种情况:
            - 如果你自己不想自定义,也不用返回给前端响应结果,只想在控制台看到异常
                    IllegalStateException用于抛出查过来的用户为空时候的异常
                    表示“数据状态不合法”,适合业务逻辑校验(如订单不存在):
                    java
                    User user = userDao.findById(userId);
                    if (user == null) {
                        throw new IllegalStateException("用户不存在"); // ✅ 标准异常,无需自定义
                    }

                    IllegalArgumentException用于想要再service判断请求此参数的时候
                    当方法参数明显无效或违反基本约定时抛出:
                    public User getUserById(Long userId) {
                        if (userId == null || userId <= 0) {
                            throw new IllegalArgumentException("用户ID必须为正数");
                        }
            - 如果想要自己定义具体的不同类型异常,并响应给前端,用rbac业务里面的异常处理方法
                - 注意这里异常处理可以放在controller抛出,或者service抛出,我感觉还是再service
                   比较符合各类校验。


(3)补一个mybatis查询结果的常见情况
查询方法	返回值(无数据时)	判断方式
- User findById(Long id)	null	if (user == null)
- List<User> selectList()	空集合 ([])	if (list.isEmpty())
- Map<String, User> selectMap()	空 Map ({})	if (map.isEmpty())


6.
4.24 字典类型表的crud写完了
     准备些字典数据表的crud


7.
4.24晚上仔细看了看前后端分离和不分离区别
- 前后端不分离特征:
    - 路由控制权再controller层,controller层既要返回或者跳转页面路由还要把数据返回到页面上
    - 数据绑定:返回的页面中的数据由后端程序员绑定插入(jsp可能还会混合java代码)。由后端程序员决定插入数据到哪里。
    - 页面渲染:页面由服务器渲染完成
总体上:前端就写三大件,然后把三大件给后端。
    -后端如果用jsp,后端程序员要把html转为jsp,开发。
    -后端如果用thymlef模板,后端程序员不用转为jsp,直接再html里面加属性,绑数据。
    注意:这两种都是前后端不分离的情形,数据绑定都是由后端决定的。

-前后端分离特征:
    - 路由控制权在前端,前端控制页面路由的跳转,调用后端urlAPI。
    - 数据绑定自由,后端只返回数据格式json,前端获取到数据,自行决定如何展示,展示多少。
    - 页面渲染,前端页面渲染由浏览器完成。



7.今天写删除和更新字典数据的时候,发现很省力的地方。
- 删除的service层的删除返回类型void,只在controller层返回成功就行。
- 更新的service层更新返回row,只在controller层判断row就行,
原来是在service层判断row,在返回boolean类型,controller在判断boolea,这样只判断一次row更方便。
- 添加和查询该判断还是要判断的,就删除和修改可以省力点。

8.
在 MySQL 数据库中,DATE_FORMAT函数的语法为DATE_FORMAT(date, format),
其中date是要格式化的日期或日期时间表达式,format是指定的格式字符串。
- DATE_FORMAT(NOW(), '%Y-%m-%d')会将当前时间按照年-月-日的格式进行显示,如2025-04-25。
- 注意:%y表示两位,%Y表示四位。

9.
<if test="status != null and status != ''" >status = #{status},</if>
<if test="remark != null and remark != ''">remark = #{remark},</if>
再次巩固这里
- 前端不写任何东西,后端sql里面得到的是''空字符串
- 前端json中删除这个字段,后端sql里没有是null

10.throw new ServiceException(String.format("%1$s已经被分配,无法删除", dictType.getDictName()));
String.fommat()里面%1$s,别忘了s,,String.format("%1$s已经被分配,无法删除", dictType.getDictName()) 这行代码的作用是将 dictType.getDictName() 的值插入到格式字符串中 %1$s 的位置,生成一个新的字符串,

11.截至2025/4/25,字典数据表和字典类型表,基本的缓存已经全部完成和测试完成。
接下来,看那个缓存注解和刷新缓存,重置缓存的方法。

12.截至2025/4/25晚上22.46,缓存系列全部写完测完。

13.明天尽量把限流加进来。4.26,限流成功熟悉并加入

14.补充一下第七点前后端分离的情况
不论是前后端分离还是不分离,前端都是通过浏览器的网络接口向后端发送请求的。
只不过前后端不分离的html代码中的数据是由后端服务器生成的,js什么的都是前端写的,运行在浏览器里面。
- 前后端分离,前端服务器,后端服务器
1.浏览器根据输入的地址向服务器(前端服务器或与前端资源所在位置对应的服务器)发送请求,获取前端的 HTML、CSS、JavaScript 等静态资源。
2.浏览器接收并解析这些资源,构建出页面的初始结构和样式,并执行 JavaScript 代码来初始化页面的交互逻辑等。
3.当用户在页面上进行操作,触发与后端数据交互的请求时,浏览器会根据前端代码中定义的逻辑,向后端服务器发送请求,请求中通常会包含相关的参数和数据。
4.后端服务器接收到请求后,进行相应的处理,如查询数据库、进行业务逻辑计算等,然后将处理结果以 JSON、XML 等格式的数据响应给浏览器。
5.浏览器接收后端返回的数据后,会将数据交给前端的 JavaScript 代码进行处理。前端 JavaScript 代码会根据数据来更新页面的内容、样式或执行其他交互操作,而不是将数据交给前端服务器处理。前端服务器主要负责提供静态资源,在前后端分离架构中,一般不会处理后端返回给浏览器的数据。
6.所以说前端服务器只是存放静态资源用的,处理后端数据还是在浏览器里面根据js代码处理

- 前后端不分离,在浏览器上输入地址,直接访问后端服务器,后端服务器返回生成的页面和数据给浏览器解析。

- 浏览器是一个软件应用程序,负责解析前端代码,前端代码运行的环境。
- 前端是设计页面的,编写三大件代码,设计后由浏览器解析代码并渲染在浏览器显示屏上。
渲染是指将 HTML、CSS 和 JavaScript 代码转换为用户可见的页面的过程

踩坑记录

1.Another Redis-desktop-manager的json格式是严格的json格式,数值后面不能有L后缀,否则无法变成json格式,这里注意一下。但是redis-desktop-manager这个散打选手居然可以解析,虽然他太破烂,机制不够严谨。

这个Another Redis-desktop-manager是真好用,界面无敌,优雅极了。

posted @ 2025-04-28 21:00  JSESSIONID  阅读(9)  评论(0)    收藏  举报