Redis的二八定律

本文介绍Redis常用命令,并通过实例展示了如何利用Redis缓存机制优化网站性能,减少数据库压力,提高数据访问速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

常用命令

1、setex key 有效时间 value ----------意思就是添加并设置该键值对的存活时间
2、mset key1 value1 key2 value2 key3 value3 ....... -----------------意思就是一次性添加多个键值对
3、getset oldKey newValue -------------意思就是重新设置已存在的key的值,返回被覆盖的旧值
4、getrange key startIndex endIndex -----------意思就是获取该key对应的值的指定子字符串(起始索引从0开始)
5、mget key1 key2...... -------------意思就是一次性获取多个见对应的值
6、append key newStr ----------意思就是给已存在的字符串追加新子字符串
7、strlen key -------计算指定字符串的长度
8、expire key 10 -------意思就是设置该key的字符串的过期时间,经过10秒自动删除(过期)
9、ttl key --------查看该key的有效时长
10、ping ----------测试当前连接是否正常
11、dbsize ------------返回当前数据库中key的总数目
12、info -------查看当前连接的服务器信息和统计
13、flushdb ------------清空当前选择的数据库中所有数据
14、flushall ---------清空所有数据库中的数据。
 
 
接着给大家分享一下redis它是如何在实际项目中进行应用的,如有不妥,希望各位能够留言指正,谢谢。
缓存的应用:网站访问数据的特点大多数呈现在"二八定律":80%的业务访问集中在20%的数据上。这时为了减轻数据的压力和提高网站的数据访问速度,则可以使用缓存机制来优化网站。
下面我就直接给大家上代码了,这是我之前测试redis缓存中的数据是否能够访问成功,而写的一点测试代码,献丑了。
  1 package com.itheima.store.service.impl;
  2 
  3 import java.sql.SQLException;
  4 import java.util.List;
  5 
  6 import com.itheima.store.dao.CategoryDao;
  7 import com.itheima.store.dao.impl.CategoryDaoImpl;
  8 import com.itheima.store.domain.Category;
  9 
 10 /**
 11  * 分类模块:业务层的实现类。
 12  * */
 13 
 14 import com.itheima.store.service.CategoryService;
 15 import com.itheima.store.utils.BeanFactory;
 16 import com.itheima.store.utils.DBUtil;
 17 import com.itheima.store.utils.JedisUtils;
 18 
 19 import net.sf.json.JSONArray;
 20 import redis.clients.jedis.Jedis;
 21 
 22 @SuppressWarnings("all")
 23 public class CategoryServiceImpl implements CategoryService {
 24 
 25     // @Override
 26     // 异步加载查询所有分类的方法:
 27     public List<Category> findAllCategory() throws Exception {
 28         // CategoryDao dao = new CategoryDaoImpl();
 29         CategoryDao dao = (CategoryDao) BeanFactory.getBean("CategoryDao");
 30         return dao.findAllCategory();
 31     }
 32 
 33     @Override
 34     // 缓存技术查询所有分类的方法:
 35     /*
 36      * 为了提升程序的性能,在这里将加入缓存的技术(redis),将获取到的分类数据放进缓存中,当用户下次再访问时,直接从缓存中获取数据,从而
 37      * 减少了和数据库的交互。
 38      */
 39     public String findAllCategoryAjax() throws Exception {
 40         // 创建jedis对象
 41         Jedis jedis = null;
 42         try {
 43             // 获得jedis对象
 44             jedis = JedisUtils.getJedis();
 45             // 首先获取缓存中是否已经有分类数据
 46             String categoryList = jedis.get("category_list");
 47             if (categoryList == null) {
 48                 // 说明缓存中没有数据,则去数据库查询
 49                 System.out.println("---------数据库中的数据-----------");
 50                 // CategoryDao dao = new CategoryDaoImpl();
 51                 CategoryDao dao = (CategoryDao) BeanFactory.getBean("CategoryDao");
 52                 List<Category> list = dao.findAllCategory();
 53                 // 将list转成JSON格式的数据
 54                 JSONArray json = JSONArray.fromObject(list);
 55                 // 将JSON数据放进缓存中,并将查询到的数据返回给页面
 56                 jedis.set("category_list", json.toString());
 57                 return jedis.get("category_list");
 58             } else {
 59                 // 如果缓存已经有数据,则将缓存中的数据返回给页面
 60                 System.out.println("--------------缓存中的数据-----------------");
 61                 return categoryList;
 62             }
 63         } catch (Exception e) {
 64             e.printStackTrace();
 65         } finally {
 66             JedisUtils.closeJedis(jedis);
 67         }
 68         return null;
 69     }
 70 
 71     @Override
 72     // 添加分类:
 73     public void addCategory(Category category) throws Exception {
 74         CategoryDao dao = (CategoryDao) BeanFactory.getBean("CategoryDao");
 75         dao.addCategory(category);
 76         // 注意:在修改了category表后,因为缓存中的数据还没有更新,前台页面的数据也没有更新,所以一旦改变了缓存中的数据后记得将缓存清空
 77         // 清空缓存:
 78         Jedis jedis = null;
 79         try {
 80             jedis = JedisUtils.getJedis();
 81             // 删除存放分类数据的key
 82             jedis.del("category_list");
 83         } catch (Exception e) {
 84             e.printStackTrace();
 85         } finally {
 86             JedisUtils.closeJedis(jedis);
 87         }
 88     }
 89 
 90     @Override
 91     // 根据cid查询分类数据:
 92     public Category findByCid(String cid) throws Exception {
 93         CategoryDao dao = (CategoryDao) BeanFactory.getBean("CategoryDao");
 94         Category category = dao.findByCid(cid);
 95         return category;
 96     }
 97 
 98     @Override
 99     // 编辑分类数据:
100     public void editCategory(Category category) throws Exception {
101         CategoryDao dao = (CategoryDao) BeanFactory.getBean("CategoryDao");
102         dao.editCategory(category);
103         // 清空缓存:
104         Jedis jedis = null;
105         try {
106             jedis = JedisUtils.getJedis();
107             // 删除存放分类数据的key
108             jedis.del("category_list");
109         } catch (Exception e) {
110             e.printStackTrace();
111         } finally {
112             JedisUtils.closeJedis(jedis);
113         }
114     }
115 
116     @Override
117     //删除分类数据:
118     /**
119      * 注意:因为分类表和商品表有着外检约束的关系,所以在删除分类数据之前,
120      *         要先删除该分类所关联的所有商品数据或将该分类所关联的所有商品的外键改变,则牵扯到事务。
121      * */
122     public void deleteCategory(String cid) throws Exception {
123         Jedis jedis = null;
124         try {
125             //开启事务:
126             DBUtil.startTransaction();
127             CategoryDao dao = (CategoryDao) BeanFactory.getBean("CategoryDao");
128             //首先根据当前cid修改商品表中的外键为null:
129             dao.updateByCid(cid);
130             dao.deleteCategory(cid);
131             //提交事务:
132             DBUtil.commit();
133             // 清空缓存:
134             jedis = JedisUtils.getJedis();
135             // 删除存放分类数据的key
136             jedis.del("category_list");
137         } catch (Exception e) {
138             //回滚事务:
139             DBUtil.rollBack();
140             e.printStackTrace();
141         } finally {
142             JedisUtils.closeJedis(jedis);
143         }
144     }
145 
146 }

 

转载于:https://www.cnblogs.com/1315925303zxz/p/6415890.html

<think>嗯,用户想知道Redis中ZSet的底层实现结构。我记得ZSet同时使用了跳表(skiplist)和字典(dict)。那这两个结构是怎么配合的呢?首先,跳表是一种有序的数据结构,支持快速查找和范围操作,而字典提供了O(1)时间复杂度的键值查询。这样设计的好处是结合了两种数据结构的优点,既保证了高效的查询,又支持范围操作。 需要确认跳表和字典如何保持数据一致性。根据引用的资料,zset结构里同时包含跳表和字典,元素通过指针共享,所以不会有重复存储的问题。这样内存使用上更高效。 另外,用户可能想知道为什么选择跳表而不是B+树。根据引用[2],跳表的时间复杂度与平衡树相当,但实现更简单,空间利用率更高,且更适合内存数据库。B+树更适合磁盘IO优化的场景,比如MySQL,而Redis作为内存数据库,跳表更适合其需求。 还要解释插入和查询的具体过程。比如插入时,跳表需要找到合适的位置并随机生成层数,字典则更新键值对。查询时,字典直接返回分值,跳表处理范围查询。可能用户会问为什么不用红黑树?跳表的并发性能更好,维护相对简单。 需要确保回答结构清晰,分点说明跳表和字典的作用,结合引用中的信息,说明它们的协同工作原理,以及选择跳表的原因。同时生成相关问题,比如优化方法、对比B+树等,帮助用户深入理解。</think>### Redis ZSet底层数据结构实现原理 Redis的ZSet(有序集合)通过**跳表(SkipList)**和**字典(Dict)**两种数据结构协同实现,兼顾高效查询和范围操作的需求。以下是具体实现细节: --- #### 1. **数据结构定义** ZSet的定义如下: ```c typedef struct zset { zskiplist *zsl; // 跳表,用于支持范围操作和有序性 dict *dict; // 字典,用于实现O(1)的键值查询 } zset; ``` - **跳表(zskiplist)**:存储有序的元素及其分值(score),支持快速插入、删除和范围查询。 - **字典(dict)**:以元素为键(key)、分值为值(value),提供O(1)时间复杂度的单元素查询。 --- #### 2. **跳表的核心作用** 跳表通过多层链表实现高效的有序操作: - **节点结构**:每个跳表节点包含: ```c typedef struct zskiplistNode { sds ele; // 元素值(字符串) double score; // 分值(用于排序) struct zskiplistNode *backward; // 后退指针 struct zskiplistLevel { struct zskiplistNode *forward; // 前进指针 unsigned long span; // 跨度(用于范围查询优化) } level[]; // 多层索引 } zskiplistNode; ``` - **插入过程**:新节点的层数由**随机算法**生成(如幂次定律),平均时间复杂度为$O(\log n)$[^1]。 - **范围操作**:支持`ZRANGE`、`ZRANK`等命令,时间复杂度为$O(\log n + k)$(k为返回元素数量)[^2]。 --- #### 3. **字典的核心作用** 字典通过哈希表实现快速单元素查询: - **键值对存储**:键为元素(如字符串),值为分值(如浮点数)。 - **查询优化**:例如`ZSCORE`命令直接从字典中获取分值,时间复杂度为$O(1)$。 --- #### 4. **协同工作原理** - **数据一致性**:跳表和字典共享元素值和分值的存储(通过指针引用),避免内存冗余。 - **插入示例**: 1. 向字典中插入键值对`(element, score)`。 2. 向跳表中插入节点,根据`score`排序。 - **删除示例**: 1. 从字典中删除键`element`。 2. 从跳表中删除对应节点。 --- #### 5. **为何选择跳表而非B+树?** - **时间复杂度**:跳表的查询、插入、删除均为$O(\log n)$,与B+树相当。 - **实现复杂度**:跳表无需复杂的旋转或再平衡操作,代码更简单。 - **内存效率**:跳表的索引层通过概率生成,空间利用率更高。 - **适用场景**:B+树适合磁盘IO优化(如数据库),而Redis作为内存数据库,跳表更契合其需求。 --- #### 6. **性能优势** - **范围查询**:跳表的双向链表特性支持快速范围遍历。 - **并发优化**:跳表的分层结构更易实现无锁并发(如Redis 6.0的多线程IO模型)。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值