Redis学习笔记:列表类型
一、概述
redis的列表类型可以存储一个有序的字符串列表,内部实现是一个双向链表,允许用户从两端插入元素。所以向两端插入数据的速度是极快的,而且获取数据时也是越接近两端速度越快,一个列表最多能容纳2^32 - 1
个元素。
二、命令
2.1 在两端插入元素
LPUSH key value [value ...]
:在列表的左端插入元素。RPUSH key value [value ...]
:在列表的右端插入元素。
返回值表示增加元素后的列表长度。
redis的列表类型可以存储一个有序的字符串列表,内部实现是一个双向链表,允许用户从两端插入元素。所以向两端插入数据的速度是极快的,而且获取数据时也是越接近两端速度越快,一个列表最多能容纳2^32 - 1
个元素。
LPUSH key value [value ...]
:在列表的左端插入元素。RPUSH key value [value ...]
:在列表的右端插入元素。返回值表示增加元素后的列表长度。
Redis
本生就是一个字典类型的键值关系数据库,结构为:
而其中还有一种散列类型的数据结构散列
,它也是一种字典结构,存储了字段关系的映射。
散列就像是一个小的redis一样,只不过这个小型redis不支持其他类型,只能是字符串。
Read 23 byte data:HelloWorld
HelloMaQian
## 四、关于lseek
lseek用于设置文件指针的位置,同时也可以查看当前指针所处的位置。
如果设置的文件指针超过了文件范围,系统将会给文件申请更多的内存空间来存储这些超出的文件数据,但这要求系统要在指针所指向的位置进行一次写操作。
int main() {
int fd, ret;
const char *s1 = "abcdefghij";
const char *s2 = "ABCDEFGHIJ";
fd = open("test.hole", O_WRONLY | O_CREAT | O_TRUNC, 0755);
if (-1 == fd)
err_sys("open file error");
if (write(fd, s1, 10) != 10)
err_sys("write s1 error");
if ((ret = lseek(fd, 0, SEEK_CUR)) < 0)
err_sys("lseek error");
printf("localtion: %d\n", ret); // 打印当前的指针位置 10
if ((ret = lseek(fd, 1000, SEEK_SET)) < 0)
err_sys("lseek error");
printf("localtion: %d\n", ret); // 移动后的位置 1000
if (write(fd, s2, 10) != 10)
err_sys("write s2 error");
close(fd);
return 0;
}
运行程序后输出:
./a.out
localtion: 10
localtion: 1000
ll test.hole
-rwxr-xr-x 1 ma ma 1010 May 18 11:18 test.hole # 文件大小1010字节
### 4.1 使用lseek生成指定大小的文件
根据上面所描述的`lseek`的特性,文件指针超出时会自动申请空间,因此我们可以通过它来生成一个指定大小的文件。
const int BT_SIZE = 1;
const int KB_SIZE = 1 << 10;
const int MB_SIZE = 1 << 20;
const int GB_SIZE = 1 << 30;
/*
int parser_size(const char *size)
{
int i = 0, n = 0;
char ch; // 遍历每一个字符
while ((ch = size[i]))
{
if ((''a'' <= ch && ch <= ''z'') || (''A'' <= ch && ch <= ''Z''))
{
if(size[i + 1])
err_quit("invalid input: %s", size);
switch (ch)
{
case ''b'':
case ''B'':
return BT_SIZE * n;
case ''k'':
case ''K'':
return KB_SIZE * n;
case ''m'':
case ''M'':
return MB_SIZE * n;
case ''g'':
case ''G'':
return GB_SIZE * n;
default:
err_quit("invalid input: %c", ch);
}
}
else if (''0'' <= ch && ch <= ''9'')
{
n = 10 * n + ch - ''0'';
}
else
{
err_quit("invalid input: %s", size);
}
i++;
}
return n;
}
int main(int argc, char **argv)
{
if (argc < 3)
err_quit("Usage: ./mkfile filename size");
int sz = parser_size(argv[2]);
int fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0755);
if (-1 == fd)
err_sys("crate file error");
// 移动到指定位置的前一个字节
if (-1 == lseek(fd, sz - 1, SEEK_SET))
err_sys("create file error");
// 写入一个字节申请内存块
if (1 != write(fd, " ", 1))
err_sys("write data error");
close(fd);
return 0;
}
根据输入即可生成指定大小的文件:
mkdir debug && gcc main.c /apue.* -o debug/app
./debug/app test1 1g
./debug/app test2 2m
./debug/app test3 3k
./debug/app test4 4
ll
total 32K
drwxrwxr-x 2 ma ma 4.0K May 18 14:40 debug
-rw-rw-r-- 1 ma ma 1.7K May 18 14:39 main.c
-rw-rw-r-- 1 ma ma 1.7K May 18 14:35 main.c.orig
-rw-rw-r-- 1 ma ma 311 May 18 14:22 Makefile
-rwxr-xr-x 1 ma ma 1.0G May 18 14:41 test1
-rwxr-xr-x 1 ma ma 2.0M May 18 14:41 test2
-rwxr-xr-x 1 ma ma 3.0K May 18 14:41 test3
-rwxr-xr-x 1 ma ma 4 May 18 14:41 test4
不过对于文件的大小有个限制,文件最多只能`2G+`,因为此时计算出来的`sz`大小会溢出。
给网站加了CDN
后,网页的部分字体加载不出,同时一些图标也会显示异常:
控制台报以下错误:
Access to Font at "http://test.dyxmq.cn/wp-content/themes/chuxia3.0/fonts/iconfont.ttf" from origin "http://www.dyxmq.cn" has been blocked by CORS policy: No "Access-Control-Allow-Origin" header is present on the requested resource. Origin "http://www.dyxmq.cn" is therefore not allowed access. The response had HTTP status code 404
任何一门程序语言都离不开位运算这个功能,redis虽然不是一门编程语言,但也是一个和编程密切关联的工具。因此位运算自然也是redis中不可或缺的功能。
redis中位运算相关的方法:
GETBIT key offset
: 获取第offset位的bit,不存的的比特位返回0。SETBIT key offset value
: 给第offset位设置成value。BITCOUNT key [start] [end]
: 计算key中1的个数。BITOP operation destkey key [key]
: 执行位操作,位操作包含与(AND)
、或(OR)
、异或(XOR)
以及 非(NOT)
。BITPOS key value [start] [end]
: 查询key
中第一次出现value
的位置,start
和end
表示字符的开始和结束位置。字符串是redis中的基本数据类型之一,能存储任何形式的字符串,包括二进制数据。同时,它还可以进行字符串运算、数据运算和位运算等操作。一个字符串最大能有512M。
字符串主要的操作命令有两个:
GET KEY
: 如果KEY
存在就返回对应的值,如果不存在则返回空值nil
。SET KEY VALUE
: 给KEY
设置值为VALUE
,如果KEY
已经存在则更新值。+
1 row in set (0.00 sec)
当要更新数据的时候根据带上版本号更新:
mysql> update lock_test set name = "xiaoming", version = version + 1 where id = 1 and version = 0;
Query OK, 1 row affected (0.03 sec)
Rows matched: 1 Changed: 1 Warnings: 0
第二个终端再根据`0` 的版本号更新数据就不会操作成功:
mysql> update lock_test set name = "xxxxxx", version = version + 1 where id = 1 and version = 0;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0 -- 影响行数为0
+
1 row in set (0.00 sec)
当查询没有明确指定主键字段值时,锁的范围是整张表。例如我们使用终端一通过`name="maqian"` 来查询的时候,整个表都会被锁住,其他事务查询任何内容都会失败:
mysql> select * from lock_test where name = "xiaoming" for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
两个事务同时更新一行数据,第一个事务正常更新,第二个事务中途退出回滚数据到初始状态,导致第一个事务更新失效。
如:银行卡存储了用户甲的余额4000,此时事务A和B同时开始更新余额,事务A将余额更新到5000后正常退出,事务B执行出错导致更新失败,然后回滚余额到开始的状态4000。于是就产生了第一类丢失更新。