redis怎么缓存sql数据

redis怎么缓存sql数据,第1张

利用redis做缓存服务器来缓解数据库查询压力是非常有效也是非常有必要的, 当用户第一次点击页面的时候查询数据库, 然后将查询结果缓存在redis服务器中,缓存时间随你的数据改变时间而定,这样可大大降低数据库压力;下面是具体函数方法;

public function getSqlVal(){

//获取参数列表,这个参数随你需求而定,一般可能需要传入dbname,查询方式如fetchAll,查询语句等

$argv = func_get_args();

//假设这里现在只传入dbName和sql语句

$dbName = $argv[0];

$sql = $argv[1];

//现在把这个参数列表转成md5之后作为存redis的key值

$md5SqlKey = MD5(serialize($argv));

//下面通过一个redis函数来进行存取数据

$res = getRedisData($md5SqlKey);

//如果取到数据,说明已经缓存在redis服务器中, 直接取数据就好, 如果没有数据, 则再去数据库查询数据,再讲查询的数据存在redis服务器中

if(!empty($res)) {

return $res;

}

//后面是查询数据库 *** 作,查询结果返回在$res中

getRedisData($md5SqlKey,$res); //讲返回结果存在redis中

return $res;

}

public function getSqlVal(){

//获取参数列表,这个参数随你需求而定,一般可能需要传入dbname,查询方式如fetchAll,查询语句等

$argv = func_get_args();

//假设这里现在只传入dbName和sql语句

$dbName = $argv[0];

$sql = $argv[1];

//现在把这个参数列表转成md5之后作为存redis的key值

$md5SqlKey = MD5(serialize($argv));

//下面通过一个redis函数来进行存取数据

$res = getRedisData($md5SqlKey);

//如果取到数据,说明已经缓存在redis服务器中, 直接取数据就好, 如果没有数据, 则再去数据库查询数据,再讲查询的数据存在redis服务器中

if(!empty($res)) {

return $res;

}

//后面是查询数据库 *** 作,查询结果返回在$res中

getRedisData($md5SqlKey,$res); //讲返回结果存在redis中

return $res;

}

答:

Redis的key的获取

redis的命令keys() 可以获取所有的key。但是此种方式当数据量大的时候,会产生阻塞的情况。 redis的key还可以通过scan命令获取key。

        String是redis最基础和最常用的数据结构,其值最大能存储 512MB,可以是简单字符串、复杂的xml/json的字符串、二进制图像或者音频的字符串、以及可以是数字的字符串。String底层使用的是SDS,是Redis的一种基本数据结构,主要是用于存储字符串和整数。

    21  set命令  set key value

        用于设置给定key的值,如果key存储了其他值,覆盖写入,无视类型。

    22 get命令 get key

        获取指定key的值,如果key不存在返回nil

    23 getset命令 get key [value]

        该命令用于获取指定的key的旧值,然后按照新值对key进行赋值。当key中没有旧值的时候返回nil。

    24 mget命令 get key1 [key2 keyN]

        返回多个key的值,某个key不存在时返回nil

    25 decr命令 decr key

        对key对应的数字做减1 *** 作。如果key不存在,那么在 *** 作之前,这个key对应的值会被置为0。如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。

    26 incr命令 incr key

        对key对应的数字做减1 *** 作。如果key不存在,那么在 *** 作之前,这个key对应的值会被置为0。如果key有一个错误类型的value或者是一个不能表示成数字的字符串,就返回错误。

    27 append命令 append key value

    如果 key 已经存在,并且值为字符串,那么这个命令会把 value 追加到原来值(value)的结尾。 如果 key 不存在,那么它将首先创建一个空字符串的key,再执行追加 *** 作,这种情况 APPEND 将类似于 SET *** 作。返回append后字符串值(value)的长度。

    31 SDS动态字符串

        struct sdshdr {

            unsigned int len;

            unsigned int free;

            char buf[];

        }

        其中,buf表示数据空间,用于存储字符串;len表示buf中已占用的字节数;free表示空闲的字节数。

    32 新的SDS结构

        增加了一个flags来标识类型,用一个字节(8位)来存储,前3位表示字符串的类型;剩余5位,存储长度小于32的段字符串。

        创建 SDS 的大致流程是这样的:首先根据字符串长度计算得到 type,根据 type 计算头部所需长度,然后动态分配内存空间。

        注意:① 创建空字符串时,SDS_TYPE_5 被强制转换为 SDS_TYPE_8(原因是创建空字符串后,内容可能会频繁更新而引发扩容 *** 作,故直接创建为 sdshdr8)

                    ②长度计算有 +1 *** 作,因为结束符 \0 会占用一个长度的空间。

                    ③返回的是指向 buf 的指针 s。

    41 session共享

    42 计数器(商品浏览记录)

     43 访问限速

    list类型用来存储多个有序的字符串,列表当中的每一个字符看做一个元素,一个列表当中可以存储有一个或者多个元素,redis的list支持存储2^32次方-1个元素。

    Redis可以从两端push和pop元素,支持读取指定范围或者制定下表的元素。list是一种灵活的链式结构,可以充当队列或者栈的角色。

    list的元素是有序的,且列表内的元素是可以重复的。

    注意:Redis32以前,列表底层的编码是ziplist(压缩列表)和linkedlist(双向列表)实现的,因为双线列表占用的内存比压缩列表多,所以当创建新的列表键时,列表会优先考虑用压缩列表,只有在需要的时候才会转换到双向列表实现。32以后重新引入了一个quicklist,列表底层都是有quicklist实现,quicklist是一个由ziplist组成的双向列表,每个节点使用ziplist来存储数据。

       21 Lpush命令 lpush key value

        将一个或多个值插入到列表头部。 如果 key 不存在,则创建list,然后再插入数据 *** 作。 当 key 存在但不是列表类型时,返回一个错误。

    22 Rpush命令 rpush key value

        将一个或多个值从list的尾部插入

    23 Blpop命令 blpop key seconds

        Blpop是取出列表的第一个元素,如果list中没有元素则会一直等到到超时,或者发现有数据为止,seconds是指定多少秒返回。如没有数据,则返回nil。

        同理,Bropo为移除list列表的最后一个元素

    24 Linsert命令 linsert key before/after val1 val2

        在list列表的某一个元素前或者后插入另外一个元素。当指的的元素不存在时,不执行任何动作。如果列表不存在时,视为空列表,不执行任何动作。

    25 Lindex命令 lindex key index

        通过链表的下标获取列表中的元素,可以是-1表示链表最后一个元素,-2代表倒数第二个元素,没有返回nil

    26 Llen命令 llen key

        返回list的长度,如果list不存在,返回0

    27 Lrange命令

        返回指定list区间内的元素,区间以偏移量start和end决定。其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。 也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

    51 队列秒杀抢购

        list类型的lpop和rpush(或者反过来,lpush和rpop)能实现队列的功能,故而可以用Redis的list类型实现简单的点对点的消息队列。不过不推荐在实战中这么使用,因为现在已经有Kafka、NSQ、RabbitMQ等成熟的消息队列了,它们的功能已经很完善了,除非是为了更深入地理解消息队列,不然没必要去重复造轮子。

    52 排行榜

        list类型的lrange命令可以分页查看队列中的数据。可将每隔一段时间计算一次的排行榜存储在list类型中。只有定时计算的排行榜才适合使用list类型存储,与定时计算的排行榜相对应的是实时计算的排行榜,list类型不能支持实时计算的排行榜。

 Redis的数据类型

Redis的数据类型共有五种:string,list,hash,set,zset;

String 字符串相对来说做平常,key-value,类似是hashmap的用法;

List 队列,可以双向的存值,设计时,也可以简单用来当队列模式;

Hash 字典,一个key 对应多个值;

Set 无序的集合;

Zset 有序的集合;

列表 list

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)

列表 list—— 基本命令

lpush

语法:lpush key value [value„]

作用:将一个或多个值 value 插入到列表 key 的表头(最左边),从左边开始加入值,从左到右的顺序依次插入到表头

返回值:数字,新列表的长度

rpush

语法:rpush key value [value„]

作用:将一个或多个值 value 插入到列表 key 的表尾(最右边),各个 value 值按从左到右 的顺序依次插入到表尾

返回值:数字,新列表的长度

lrange

语法:lrange key start stop

作用:获取列表 key 中指定区间内的元素,0 表示列表的第一个元素,以 1 表示列表的第二个元素;

start ,

stop 是列表的下标值,也可以负数的下标, -1 表示列表的最后一个元素, -2 表示列表的倒 数第二个元素,以此类推。

start ,stop 超出列表的范围不会出现错误。

返回值:指定区间的列表

lindex

语法:lindex key index

作用:获取列表 key 中下标为指定 index 的元素,列表元素不删除,只是查询。

0 表示列表的第一个元素,以 1 表示列表的第二个元素;

start ,

stop 是列表的下标值,也可以负数的下标, -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

返回值:指定下标的元素;index 不在列表范围,返回nil

llen

语法:llen key

作用:获取列表 key 的长度 返回值:数值,列表的长度; key 不存在返回0

lrem

语法:lrem key count value

作用:根据参数count的值,移除列表中与参数value相等的元素,

count>0,从列表的左侧向右开始移 除;

count<0从列表的尾部开始移除;

count=0 移除表中所有与value相等的值。

返回值:数值,移除的元素个数

lset

语法:lset key index value

作用:将列表 key 下标为 index 的元素的值设置为 value。

返回值:设置成功返回 ok ; key 不存在或者 index 超出范围返回错误信息

linsert

语法:linsert key BEFORE(前)|AFTER(后) pivot value

作用:

将值value插入到列表key当中位于值pivot之前或之后的位置。

key不存在,pivot不在列表中, 不执行任何 *** 作。

返回值:命令执行成功,返回新列表的长度。没有找到 pivot 返回 -1, key 不存在返回 0。

RPOP key

移除列表的最后一个元素,返回值为移除的元素。

RPOPLPUSH source destination

移除列表的最后一个元素,并将该元素添加到另一个列表并返回

LPOP key

移除列表的第一个元素,返回值为移除的元素。

使用场景

1 消息队列

队列模式的情况下,可以使用,左进右出的原则,但不建议使用,因为现在市面上有很多成熟的消息中间件,没有必要造轮子;

2.排行榜

某一段时间统计数据的排行榜可以放在list里面,需要分页的话,也可以使用lrange start stop实现;

3 list类型的lpush命令和lrange命令能实现最新列表的功能,每次通过lpush命令往列表里插入新的元素,然后通过lrange命令读取最新的元素列表,如朋友圈的点赞列表、评论列表。

但是,并不是所有的最新列表都能用list类型实现,因为对于频繁更新的列表,list类型的分页可能导致列表元素重复或漏掉,举个例子,当前列表里由表头到表尾依次有(E,D,C,B,A)五个元素,每页获取3个元素,用户第一次获取到(E,D,C)三个元素,然后表头新增了一个元素F,列表变成了(F,E,D,C,B,A),此时用户取第二页拿到(C,B,A),元素C重复了。只有不需要分页(比如每次都只取列表的前5个元素)或者更新频率低(比如每天凌晨更新一次)的列表才适合用list类型实现

哈希类型hash

redis hash是一个 string 类型的 field 和 value 的映射表,hash特别适合用于存储对象,每个 hash 可以存储 232 - 1键值对(40多亿);

哈希类型 hash—— 基本命令

hset /hget /hmset /hmget /hgetall /hkeys /hvals /hexists

hset

语法:hset hash 表的key field value

作用:将哈希表 key 中的域 field 的值设为value ,如果 key 不存在,则新建 hash 表,执行赋值,如果有 field ,则覆盖值。

返回值: ①如果 field 是 hash 表中新field,且设置值成功,返回 1 ②如果 field 已经存在,旧值覆盖新值,返回0

hget

语法:hget key field

作用:获取哈希表 key 中给定域 field 的值

返回值:field 域的值,如果 key 不存在或者 field 不存在返回nil

hmset

语法:hmset key field value [field value„]

说明:同时将多个field-value(域-值)设置到哈希表key中,此命令会覆盖已经存在的field, hash表key不存在,创建空的hash表,执行hmset

返回值:设置成功返回ok, 如果失败返回一个错误

hmget

语法:hmget key field [field„]

作用:获取哈希表key中一个或多个给定域的值

返回值:返回和field顺序对应的值,如果field不存在,返回nil

hgetall

语法:hgetall key

作用:获取哈希表key中所有的域和值

返回值:以列表形式返回hash中域和域的值 ,key不存在,返回空hash

hdel

语法:hdel key field [field„]

作用:删除哈希表 key 中的一个或多个指定域 field,不存在 field 直接忽略

返回值:成功删除的 field 的数量

hkeys

语法:hkeys key

作用:查看哈希表 key 中的所有 field 域

返回值:包含所有 field 的列表,key 不存在返回空列表

hvals

语法:hvals key

作用:返回哈希表中所有域的值 返回值:包含哈希表所有域值的列表,key 不存在返回空列表

hexists

语法:hexists key field

作用:查看哈希表 key 中,给定域 field 是否存在

返回值:如果 field 存在,返回 1, 其他返回0

使用场景

1、购物车

以用户id为key,商品id为field,商品数量为value,恰好构成了购物车的3个要素,如下图所示。

2、hash还是比较适合存储对象(key field value)或者是字典表(type,key,vlaue),刚好符合对象的要素,但string + json也可以存储,两则比较有什么区别?

 String  + json    Hash

效率很  高           高

容量      低           低

灵活性  低           高

序列化  简单       复杂

使用Redis的脚本功能实现Redis中数据简单查询,有需要的朋友可以参考下。

在Redis的设计中,key是一切,对于Redis是可见的,而value对于Redis来说就是一个字节数组,Redis并不知道你的value中存储的是什么,所以要想实现比如

‘select from users where userlocation="shanghai"’

这样的查询,在Redis是没办法通过value进行比较得出结果的。但是可以通过不同的数据结构类型来做到这一点。比如如下的数据定义

users:1 {name:Jack,age:28,location:shanghai} users:2 {name:Frank,age:30,location:beijing} users:location:shanghai [1]

其中users:1 users:2 分别定义了两个用户信息,通过Redis中的hash数据结构,而users:location:shanghai 记录了所有上海的用户id,通过集合数据结构实现。这样通过两次简单的Redis命令调用就可以实现我们上面的查询。

Jedis jedis = jedisPoolgetResource(); Set<String> shanghaiIDs = jedissmembers("users:location:shanghai"); //遍历该set // //通过hgetall获取对应的user信息 jedishgetAll("users:" + shanghaiIDs[0]);

通过诸如以上的设计,可以实现简单的条件查询。但是这样的问题也很多,首先需要多维护一个ID索引的集合,其次对于一些复杂查询无能为力(当然也不能期望Redis实现像关系数据库那样的查询,Redis不是干这的)。

但是Redis26集成了Lua脚本,可以通过eval命令,直接在RedisServer环境中执行Lua脚本,并且可以在Lua脚本中调用Redis命令。其实,就是说可以让你用Lua这种脚本语言,对Redis中存储的key value进行 *** 作,这个意义就大了,甚至可以将你们系统所需的各种业务写成一个个lua脚本,提前加载进入Redis,然后对于请求的响应,只需要调用一个个lua脚本就行。当然这样说有点夸张,但是意思就是这样的。

比如,现在我们要实现一个‘所有age大于28岁的user’这样一个查询,那么通过以下的Lua脚本就可以实现

public static final String SCRIPT = "local resultKeys={};" + "for k,v in ipairs(KEYS) do " + " local tmp = rediscall('hget', v, 'age');" + " if tmp > ARGV[1] then " + " tableinsert(resultKeys,v);" + " end;" + "end;" + "return resultKeys;";

执行脚本代码 Jedis jedis = jedisPoolgetResource(); jedisauth(auth); List<String> keys = ArraysasList(allUserKeys); List<String> args = new ArrayList<>(); argsadd("28"); List<String> resultKeys = (List<String>)jedisevalsha(funcKey, keys, args); return resultKeys;

注意,以上的代码中使用的是evalsha命令,该命令参数的不是直接Lua脚本字符串,而是提前已经加载到Redis中的函数的一个SHA索引,通过以下的代码将系统中所有需要执行的函数提前加载到Redis中,我们的系统维护一个函数哈希表,后续需要实现什么功能,就从函数表中获取对应功能的SHA索引,通过evalsha调用就行。

String shaFuncKey = jedisscriptLoad(SCRIPT);//加载脚本,获取sha索引 funcTableput(funcName_age, shaFuncKey);//添加到函数表中

通过以上的方法,便可以使较为复杂的查询放到Redis中去执行,提高效率。

以上就是关于redis怎么缓存sql数据全部的内容,包括:redis怎么缓存sql数据、redis获取获取key等待、Redis数据结构之string类型和list类型等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9672160.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-30
下一篇2023-04-30

发表评论

登录后才能评论

评论列表(0条)

    保存