Mysql数据转移Redis


​ 最近毕业设计上想加上一个redis,就必须要把MySQL里面的数据转移到redis当中。那么问题来了,关系型数据库的数据怎么转移到非关系型数据库中呢?然后百度MySQL数据迁移redis,然后果不其然,各个博客保持了高度统一,看那么几篇博客,几乎都是转载的,有原创的也很少。当然我也只是个小白,摸索了很久才成功了。

​ 如果百度过了的同学对events_all_time这个表很熟悉吧,哈哈。我也不多说了,原文写的没问题,也不是说没问题,是思路没问题,语法也没问题,但是实际操作后会报错,这个报错原因也不知道为啥。我在Stack Overflow上面看到的解决方法不是用的redisprotocol。对于我这个小白来说,文章里面有的地方没有解释。看起来有点费劲,搞不明白为啥这么写。然后我这篇就是先解释下redisprotocol,再说下mysql转redis命令的方法,最后说下mysql里面多条数据以什么格式,怎么存到redis。(这里附一下那个不知道被转了多少遍的events_all_time 2333)

1
2
3
4
5
6
7
CREATE TABLE events_all_time (
id int(11) unsigned NOT NULL AUTO_INCREMENT,
action varchar(255) NOT NULL,
count int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (id),
UNIQUE KEY uniq_action (action)
);

正文

百度上的mysql迁移redis的方法,看不懂的同学,结合官网的解释https://redis.io/topics/mass-insert,食用更佳哦。

​ 用redis普通的客户端插入大量数据并不好,所以官方推荐的方法是生成一个符合redis协议的text文件,用redis统一去调用。text文件可以写redis命令,也可以写redis协议。协议格式如下

1
2
3
4
5
6
*<args><cr><lf>
$<len><cr><lf>
<arg0><cr><lf>
<arg1><cr><lf>
...
<argN><cr><lf>

对应的 ‘\r’ (ASCII码13),对应的 ‘\n’ (ASCII码10)。然后那个和$符号的意义就是。号后面加数字,表示整个命令总共有多少个参数,包括命令本身。$后面加数字,表示对应的参数,有多少字节。

​ 举个栗子 SET key1 value1

转化为redis的协议就是 *3\r\n$3\r\nSET\r\n$4\r\nkey1\r\n$6\r\nvalue1\r\n

*3—>有set,key1,value1三个

$3—>后面SET有三个字节

$4—>后面key1有4个字节

$6—>后面value1有6个字节

是不是很简单^_^!!!!!

然后看看那个不知道被转了多少遍的events_to_redis.sql。明白了redis protocol之后再看这个代码,一目了然。作者的意图就是把数据库里面查询出的值,拼接成相应的命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT CONCAT(
"*4\r\n",
'$', LENGTH(redis_cmd), '\r\n',
redis_cmd, '\r\n',
'$', LENGTH(redis_key), '\r\n',
redis_key, '\r\n',
'$', LENGTH(hkey), '\r\n',
hkey, '\r\n',
'$', LENGTH(hval), '\r\n',
hval, '\r'
)
FROM (
SELECT
'HSET' as redis_cmd,
'events_all_time' AS redis_key,
action AS hkey,
count AS hval
FROM events_all_time
) AS t

最终用

mysql -h ‘ip地址’ -u’用户名’ -p’密码’ ‘database’ —skip-column-names —raw < events_to_redis.sql | redis-cli —pipe

这条命令意思就是 mysql登录后,用‘database’这个数据库, —skip-column-names(使mysql输出不包含列名) —raw(使mysql不转换字段值中的换行符),然后就是运行events_to_redis.sql,用管道传入redis-cli当中运行即可。

这里有一个问题,就是按照 *3\r\n$3\r\nSET\r\n$4\r\nkey1\r\n$6\r\nvalue1\r\n这样的方式是不行的。总是报错

ERR Protocol error: expected ‘$’, got ‘ ‘

具体原因我并不太清楚,如果有同学解决了,希望可以评论说一下,让我这个小白也学习一下。

解决方案

我最后的解决方案其实就是在前面了解了的基础上,把sql语句修改了,让mysql最终输出的格式是普通的 SET key value的格式,然后运行即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SELECT 
CONCAT(
redis_cmd,' ',
redis_key,
idval,' ',
ACTION,' ',
actionval,' ',
COUNT,' ',
countval,' '
)
FROM
(SELECT
'HSET' AS redis_cmd,
'events_all_time' AS redis_key,
id AS idval,
'action' AS ACTION,
ACTION AS actionval,
'count' AS COUNT,
COUNT AS countval
FROM
events_all_time) AS t

总而言之,不管你用的是mysql,java,python,C/C++,甚至是记事本。只要输出的格式是redis protocol或redis命令,传入redis-cli当中就可以完成这个任务。

mysql多条数据存入redis

然后对于mysql 的多条数据,我使用的是redis的hmset命令。

HMSET key field value [field value ..]

key就是表名称+id,这样查询的时候进行简单处理即可得到对应数据表一条的数据。hmset 表名+id 列名 值 列名 值 …

其实用HSET也是可以的,key就是表名称+id,然后一条数据,可以用String存上,同样简单处理也可得到数据。