通过mysql自动同步redis,通过MySQL自动同步刷新Redis

在服务端开荒进度中,一般会选拔MySQL等关系型数据库作为最后的囤积引擎,Redis其实也得以当作一种键值对型的数据库,但在有个别其实情状中,尤其是关系型结构并不适合接纳Redis直接作为数据库。那俩家伙简直能够用“男女搭配,干活不累”来描写,搭配起来使用才具一石两鸟。本篇大家就那两边怎么合理搭配以及他们中间数据怎样进展同步开展。

在服务端开拓进度中,一般会动用MySQL等关系型数据库作为最后的存款和储蓄引擎,Redis其实也得以当做壹种键值对型的数据库,但在一些其实情况中,尤其是关系型结构并不符合利用Redis直接当做数据库。那俩家伙大概能够用“男女搭配,干活不累”来描写,搭配起来使用才能一石两鸟。本篇我们就那两边怎么客观搭配以及他们中间数据怎么着进展联合张开。

在服务端开拓进程中,一般会选用MySQL等关系型数据库作为最终的积累引擎,Redis其实也足以当做1种键值对型的数据库,但在局地实在情状中,越发是关系型结构并不合乎利用Redis间接作为数据库。那俩家伙大致能够用“男女搭配,干活不累”来描写,搭配起来使用才能一箭双雕。本篇我们就那两边怎么客观搭配以及他们中间数据如何开始展览同步举办。

一般地,Redis能够用来作为MySQL的缓存层。为何MySQL最佳有缓存层呢?想象一下这么的地方:在多少个多少人在线的十二日游里,排名榜、好友关系、队列等直接关周全据的景观下,倘若一向和MySQL正面交手,多量的数码请求只怕会让MySQL筋疲力竭,以至抢先的伸手将会击穿数据库,导致整个数据服务中断,数据库品质的瓶颈将制约业务的费用;那么1旦因而Redis来做多少缓存,将大大减小查询数据的下压力。在那种作风里,当大家在作业层有多少查询必要时,先到Redis缓存中查询,如若查不到,再到MySQL数据库中询问,同时将查到的数额更新到Redis里;当我们在职业层有改换插入数据须求时,直接向MySQL发起呼吁,同时创新Redis缓存。

诚如地,Redis能够用来作为MySQL的缓存层。为啥MySQL最棒有缓存层呢?想象一下那样的景色:在三个几个人在线的游戏里,排名榜、好友关系、队列等间接关周到据的气象下,假使直白和MySQL正面交手,大批量的数额请求可能会让MySQL半死不活,以致超越的呼吁将会击穿数据库,导致整个数据服务中断,数据库品质的瓶颈将制约业务的开采;那么只要通过Redis来做多少缓存,将大大减小查询数据的下压力。在那种作风里,当我们在业务层有数量查询供给时,先到Redis缓存中询问,即使查不到,再到MySQL数据库中查询,同时将查到的多少更新到Redis里;当我们在作业层有修改插入数据需要时,直接向MySQL发起呼吁,同时立异Redis缓存。

通过mysql自动同步redis,通过MySQL自动同步刷新Redis。诚如地,Redis能够用来作为MySQL的缓存层。为啥MySQL最佳有缓存层呢?想象一下这么的现象:在叁个三人在线的游艺里,排名榜、好友关系、队列等一向关全面据的情状下,就算平素和MySQL正面交手,大批量的数额请求大概会让MySQL筋疲力竭,以至高于的恳求将会击穿数据库,导致整个数据服务中断,数据库质量的瓶颈将制约业务的支出;那么只要经过Redis来做多少缓存,将大大减小查询数据的压力。在那种作风里,当我们在业务层有多少查询要求时,先到Redis缓存中询问,假设查不到,再到MySQL数据库中询问,同时将查到的多少更新到Redis里;当大家在作业层有退换插入数据供给时,直接向MySQL发起呼吁,同时更新Redis缓存。

在地点这种作风中,有八个关键点,正是MySQL的CRUD发生后活动地立异到Redis里,那亟需通过MySQL
UDF来贯彻。具体来讲,大家把立异Redis的逻辑放到MySQL中去做,即定义三个触发器Trigger,监听CRUD这一个操作,当操作发生后,调用对应的UDF函数,远程写回Redis,所以专业逻辑只必要承受更新MySQL就行了,剩下的交付MySQL
UDF去做到。

在地方那种作风中,有3个关键点,便是MySQL的CRUD产生后自动地立异到Redis里,那须要通过MySQL
UDF来贯彻。具体来讲,我们把立异Redis的逻辑放到MySQL中去做,即定义3个触发器Trigger,监听CRUD这一个操作,当操作产生后,调用对应的UDF函数,远程写回Redis,所以职业逻辑只必要承担更新MySQL就行了,剩下的交付MySQL
UDF去完毕。

在地方那种作风中,有八个关键点,正是MySQL的CRUD爆发后自动地翻新到Redis里,那亟需经过MySQL
UDF来兑现。具体来讲,大家把立异Redis的逻辑放到MySQL中去做,即定义3个触发器Trigger,监听CRUD那些操作,当操作产生后,调用对应的UDF函数,远程写回Redis,所以专门的学问逻辑只要求负责更新MySQL就行了,剩下的交付MySQL
UDF去完结。

一. 什么是UDF

UDF,是User Defined
Function的缩写,用户定义函数。MySQL协助函数,也支持自定义的函数。UDF比存款和储蓄方法有更加高的实行作用,并且帮忙集中函数。

UDF定义了5个API:xxx_init()、xxx_deinit()、xxx()、xxx_add()、xxx_clear()。法定文书档案(http://dev.mysql.com/doc/refman/5.7/en/adding-udf.html)提交了这几个API的辨证。相关的构造体定义在mysql_com.h里,它又被mysql.h包蕴,使用时只需#include<mysql.h>就可以。他们之间的涉嫌和实施各样能够以下图来表示:

997755.com澳门葡京 1

一. 什么是UDF

UDF,是User Defined
Function的缩写,用户定义函数。MySQL辅助函数,也帮衬自定义的函数。UDF比存款和储蓄方法有更加高的实行功用,并且匡助集中函数。

UDF定义了5个API:xxx_init()、xxx_deinit()、xxx()、xxx_add()、xxx_clear()。法定文书档案(http://dev.mysql.com/doc/refman/5.7/en/adding-udf.html)提交了这一个API的认证。相关的布局体定义在mysql_com.h里,它又被mysql.h包涵,使用时只需#include<mysql.h>就可以。他们之间的关联和施行各类能够以下图来表示:

997755.com澳门葡京 2

一. 什么是UDF

UDF,是User Defined
Function的缩写,用户定义函数。MySQL匡助函数,也扶助自定义的函数。UDF比存款和储蓄方法有越来越高的施行效用,并且支持集中函数。

UDF定义了5个API:xxx_init()、xxx_deinit()、xxx()、xxx_add()、xxx_clear()。法定文书档案(http://dev.mysql.com/doc/refman/5.7/en/adding-udf.html)提交了那些API的证实。相关的构造体定义在mysql_com.h里,它又被mysql.h包蕴,使用时只需#include<mysql.h>就可以。他们之间的涉嫌和实践各样能够以下图来表示:

997755.com澳门葡京 3

1. xxx()

那是主函数,三个函数至少须求xxx(),对MySQL操作的结果在此再次来到。函数的宣示如下:

char *xxx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned
long *length, char *is_null, char *error);

long long xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
char *error);

double xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char
*error);

SQL的品种和C/C++类型的映照:

SQL Type C/C++ Type
STRING char *
INTEGER long long
REAL double

1. xxx()

那是主函数,6个函数至少须要xxx(),对MySQL操作的结果在此再次回到。函数的注解如下:

char *xxx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned
long *length, char *is_null, char *error);

long long xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
char *error);

double xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char
*error);

SQL的门类和C/C++类型的照耀:

SQL Type C/C++ Type
STRING char *
INTEGER long long
REAL double

1. xxx()

那是主函数,八个函数至少须求xxx(),对MySQL操作的结果在此重返。函数的宣示如下:

char *xxx(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned
long *length, char *is_null, char *error);

long long xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
char *error);

double xxx(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char
*error);

SQL的品类和C/C++类型的光彩夺目:

SQL Type C/C++ Type
STRING char *
INTEGER long long
REAL double

2. xxx_init()

xxx()主函数的伊始化,假若定义了,则用来检查传入xxx()的参数数量、类型、分配内部存款和储蓄器空间等伊始化操作。函数的证明如下:

my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char
*message);

2. xxx_init()

xxx()主函数的初步化,假设定义了,则用来检查传入xxx()的参数数量、类型、分配内部存款和储蓄器空间等起初化操作。函数的注脚如下:

my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char
*message);

2. xxx_init()

xxx()主函数的伊始化,借使定义了,则用来检查传入xxx()的参数数量、类型、分配内部存款和储蓄器空间等开始化操作。函数的评释如下:

my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char
*message);

3. xxx_deinit()

xxx()主函数的反起首化,如若定义了,则用来释放先导化时分配的内部存款和储蓄器空间。函数的扬言如下:

void xxx_deinit(UDF_INIT *initid);

3. xxx_deinit()

xxx()主函数的反早先化,要是定义了,则用来刑满释放解除劳教初步化时分配的内部存款和储蓄器空间。函数的表明如下:

void xxx_deinit(UDF_INIT *initid);

3. xxx_deinit()

xxx()主函数的反初阶化,如若定义了,则用来刑释早先化时分配的内部存款和储蓄器空间。函数的扬言如下:

void xxx_deinit(UDF_INIT *initid);

4. xxx_add()

在聚合UDF中屡屡调用,将参数参预聚合参数中。函数的注脚如下:

void xxx_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char
*error);

4. xxx_add()

在聚合UDF中1再调用,将参数参加聚合参数中。函数的宣示如下:

void xxx_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char
*error);

4. xxx_add()

在聚合UDF中频仍调用,将参数参与聚合参数中。函数的扬言如下:

void xxx_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char
*error);

5. xxx_clear()

在聚合UDF中再3调用,重新恢复设置聚合参数,为下一行数据的操作做筹算。函数的宣示如下:

void xxx_clear(UDF_INIT *initid, char *is_null, char *error);

5. xxx_clear()

在聚合UDF中往往调用,重新设置聚合参数,为下壹行数据的操作做计划。函数的扬言如下:

void xxx_clear(UDF_INIT *initid, char *is_null, char *error);

5. xxx_clear()

在聚合UDF中频仍调用,重新初始化聚合参数,为下一行数据的操作做打算。函数的宣示如下:

void xxx_clear(UDF_INIT *initid, char *is_null, char *error);

2. UDF函数的为主使用

在此以前,需求先安装mysql的开采包:

[root@localhost zhxilin]# yum install mysql-devel -y

小编们定义3个最简便易行的UDF主函数:

 1 /*simple.cpp*/
 2 #include <mysql.h>
 3 
 4 extern "C" long long simple_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
 5 {
 6     int a = *((long long *)args->args[0]);
 7     int b = *((long long *)args->args[1]);
 8     return a + b;
 9 }
10 
11 extern "C" my_bool simple_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
12 {
13     return 0;
14 }

鉴于mysql提供的接口是C完结的,我们在C++中利用时须求加多:

extern "C" { ... }

接下去编译成动态库.so:

[zhxilin@localhost mysql-redis-test]$ g++ -shared -fPIC -I /usr/include/mysql -o simple_add.so simple.cpp

-shared 表示编写翻译和链接时选取的是大局共享的类库;

-fPIC编写翻译器输出地方无关的目标代码,适用于动态库;

-I /usr/include/mysql 指明包含的头文件mysql.h所在的地方。

编译出simple_add.so后用root拷贝到/usr/lib64/mysql/plugin下:

[root@localhost mysql-redis-test]# cp simple_add.so /usr/lib64/mysql/plugin/

继之能够在MySQL中开创函数实践了。登入MySQL,成立关联函数:

mysql> CREATE FUNCTION simple_add RETURNS INTEGER SONAME 'simple_add.so';
Query OK, 0 rows affected (0.04 sec)

测试UDF函数:

mysql> select simple_add(10, 5);
+-------------------+
| simple_add(10, 5) |
+-------------------+
|                15 |
+-------------------+
1 row in set (0.00 sec)

能够看看,UDF准确实施了加法。

创造UDF函数的语法是 CREATE FUNCTION xxx RETU纳瓦拉NS [INTEGER/STRING/REAL]
SONAME ‘[so name]’;

除去UDF函数的语法是 DROP FUNCTION simple_add;

mysql> DROP FUNCTION simple_add;
Query OK, 0 rows affected (0.03 sec)

贰. UDF函数的中坚选用

以前,须求先安装mysql的开辟包:

[root@localhost zhxilin]# yum install mysql-devel -y

我们定义一个最简便易行的UDF主函数:

997755.com澳门葡京 4

 1 /*simple.cpp*/
 2 #include <mysql.h>
 3 
 4 extern "C" long long simple_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
 5 {
 6     int a = *((long long *)args->args[0]);
 7     int b = *((long long *)args->args[1]);
 8     return a + b;
 9 }
10 
11 extern "C" my_bool simple_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
12 {
13     return 0;
14 }

997755.com澳门葡京 5

由于mysql提供的接口是C落成的,我们在C++中应用时要求加上:

extern "C" { ... }

接下去编写翻译成动态库.so:

[zhxilin@localhost mysql-redis-test]$ g++ -shared -fPIC -I /usr/include/mysql -o simple_add.so simple.cpp

-shared 表示编写翻译和链接时行使的是大局共享的类库;

-fPIC编写翻译器输出地点无关的对象代码,适用于动态库;

-I /usr/include/mysql 指明包蕴的头文件mysql.h所在的地方。

编译出simple_add.so后用root拷贝到/usr/lib64/mysql/plugin下:

[root@localhost mysql-redis-test]# cp simple_add.so /usr/lib64/mysql/plugin/

进而能够在MySQL中制造函数实施了。登6MySQL,创设关联函数:

mysql> CREATE FUNCTION simple_add RETURNS INTEGER SONAME 'simple_add.so';
Query OK, 0 rows affected (0.04 sec)

测试UDF函数:

997755.com澳门葡京 6

mysql> select simple_add(10, 5);
+-------------------+
| simple_add(10, 5) |
+-------------------+
|                15 |
+-------------------+
1 row in set (0.00 sec)

997755.com澳门葡京 7

能够见到,UDF正确实行了加法。

创设UDF函数的语法是 CREATE FUNCTION xxx RETU奥德赛NS [INTEGER/STRING/REAL]
SONAME ‘[so name]’;

删除UDF函数的语法是 DROP FUNCTION simple_add;

mysql> DROP FUNCTION simple_add;
Query OK, 0 rows affected (0.03 sec)

二. UDF函数的大旨选拔

在此以前,供给先安装mysql的开垦包:

[root@localhost zhxilin]# yum install mysql-devel -y

我们定义2个最简便易行的UDF主函数:

997755.com澳门葡京 8

 1 /*simple.cpp*/
 2 #include <mysql.h>
 3 
 4 extern "C" long long simple_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
 5 {
 6     int a = *((long long *)args->args[0]);
 7     int b = *((long long *)args->args[1]);
 8     return a + b;
 9 }
10 
11 extern "C" my_bool simple_add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
12 {
13     return 0;
14 }

997755.com澳门葡京 9

由于mysql提供的接口是C落成的,大家在C++中应用时索要丰盛:

extern "C" { ... }

接下去编写翻译成动态库.so:

[zhxilin@localhost mysql-redis-test]$ g++ -shared -fPIC -I /usr/include/mysql -o simple_add.so simple.cpp

-shared 表示编写翻译和链接时使用的是全局共享的类库;

-fPIC编写翻译器输出地点非亲非故的目的代码,适用于动态库;

-I /usr/include/mysql 指明包含的头文件mysql.h所在的地点。

编译出simple_add.so后用root拷贝到/usr/lib64/mysql/plugin下:

[root@localhost mysql-redis-test]# cp simple_add.so /usr/lib64/mysql/plugin/

随之能够在MySQL中创造函数试行了。登入MySQL,创造关联函数:

mysql> CREATE FUNCTION simple_add RETURNS INTEGER SONAME 'simple_add.so';
Query OK, 0 rows affected (0.04 sec)

测试UDF函数:

997755.com澳门葡京 10

mysql> select simple_add(10, 5);
+-------------------+
| simple_add(10, 5) |
+-------------------+
|                15 |
+-------------------+
1 row in set (0.00 sec)

997755.com澳门葡京 11

能够看看,UDF精确实践了加法。

开创UDF函数的语法是 CREATE FUNCTION xxx RETU凯雷德NS [INTEGER/STRING/REAL]
SONAME ‘[so name]’;

去除UDF函数的语法是 DROP FUNCTION simple_add;

mysql> DROP FUNCTION simple_add;
Query OK, 0 rows affected (0.03 sec)

三. 在UDF中访问Redis

跟上述做法同样,只需在UDF里调用Redis提供的接口函数。Redis官方给出了Redis
C++ Client
(https://github.com/mrpi/redis-cplusplus-client),封装了Redis的基本操作。

源码是重视boost,必要先安装boost:

[root@localhost dev]# yum install boost boost-devel

接下来下载redis cpp client源码:

[root@localhost dev]# git clone https://github.com/mrpi/redis-cplusplus-client

选拔时需求把redisclient.h、anet.h、fmacros.h、anet.c
那八个文本考到目录下,开端编写制定关于Redis的UDF。我们定义了redis_hset作为主函数,连接Redis并调用hset插入哈希表,redis_hset_init作为起始化,检查参数个数和类型。

 1 /* test.cpp */
 2 #include <stdio.h>
 3 #include <mysql.h>
 4 #include "redisclient.h"
 5 using namespace boost;
 6 using namespace std;
 7 
 8 static redis::client *m_client = NULL;
 9 
10 extern "C" char *redis_hset(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) {
11     try {
12         // 连接Redis
13         if(NULL == m_client) {
14             const char* c_host = getenv("REDIS_HOST");
15             string host = "127.0.0.1";
16             if(c_host) {
17                 host = c_host;
18             }
19             m_client = new redis::client(host);
20         }        
21 
22         if(!(args->args && args->args[0] && args->args[1] && args->args[2])) {
23             *is_null = 1;
24             return result;
25         }
26 
27         // 调用hset插入一个哈希表
28         if(m_client->hset(args->args[0], args->args[1], args->args[2])) {
29             return result;
30         } else {
31             *error = 1;
32             return result;
33         }
34     } catch (const redis::redis_error& e) {
35         return result;
36     }
37 }
38 
39 extern "C" my_bool redis_hset_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
40     if (3 != args->arg_count) {
41         // hset(key, field, value) 需要三个参数
42         strncpy(message, "Please input 3 args for: hset('key', 'field', 'value');", MYSQL_ERRMSG_SIZE);
43         return -1;
44     }
45     if (args->arg_type[0] != STRING_RESULT  || 
46         args->arg_type[1] != STRING_RESULT  || 
47         args->arg_type[2] != STRING_RESULT) { 
48         // 检查参数类型
49         strncpy(message, "Args type error: hset('key', 'field', 'value');", MYSQL_ERRMSG_SIZE);
50         return -1;
51     }
52 
53     args->arg_type[0] = STRING_RESULT;
54     args->arg_type[1] = STRING_RESULT;
55     args->arg_type[2] = STRING_RESULT;
56 
57     initid->ptr = NULL;
58     return 0;
59 }

编写翻译链接:

[zhxilin@localhost mysql-redis-test]$ g++ -shared -fPIC -I /usr/include/mysql -lboost_serialization -lboost_system -lboost_thread -o libmyredis.so anet.c test.cpp

编写翻译时索要充足-lboost_serialization -lboost_system -lboost_thread,
表示供给链接三个动态库:libboost_serialization.so、libboost_system.so、libboost_thread.so,不然在运作时会报缺乏函数定义的谬误。

编写翻译出libmyredis.so之后,将其拷贝到mysql的插件目录下并提权:

[root@localhost mysql-redis-test]# cp libmyredis.so /usr/lib64/mysql/plugin/ & chmod 777 /usr/lib64/mysql/plugin/libmyredis.so 

成就今后登入MySQL,成立关联函数测试一下:

mysql> DROP FUNCTION IF EXISTS `redis_hset`;
Query OK, 0 rows affected (0.16 sec)

mysql> CREATE FUNCTION redis_hset RETURNS STRING SONAME 'libmyredis.so';
Query OK, 0 rows affected (0.02 sec)

先删除老的UDF,注意函数名加反引号(“)。调用UDF测试,再次回到0,施行成功:

mysql> SELECT redis_hset('zhxilin', 'id', '09388334');
+-----------------------------------------+
| redis_hset('zhxilin', 'id', '09388334') |
+-----------------------------------------+
| 0                                                     |
+-----------------------------------------+
1 row in set (0.00 sec)

开垦redis-cli,查看结果:

127.0.0.1:6379> HGETALL zhxilin
1) "id"
2) "09388334"

三. 在UDF中访问Redis

跟上述做法一点差别也没有于,只需在UDF里调用Redis提供的接口函数。Redis官方给出了Redis
C++ Client
(https://github.com/mrpi/redis-cplusplus-client),封装了Redis的基本操作。

源码是信赖boost,供给先安装boost:

[root@localhost dev]# yum install boost boost-devel

接下来下载redis cpp client源码:

[root@localhost dev]# git clone https://github.com/mrpi/redis-cplusplus-client

动用时须要把redisclient.h、anet.h、fmacros.h、anet.c
那6个公文考到目录下,开端工编织制关于Redis的UDF。我们定义了redis_hset作为主函数,连接Redis并调用hset插入哈希表,redis_hset_init作为初叶化,检查参数个数和项目。

997755.com澳门葡京 12

 1 /* test.cpp */
 2 #include <stdio.h>
 3 #include <mysql.h>
 4 #include "redisclient.h"
 5 using namespace boost;
 6 using namespace std;
 7 
 8 static redis::client *m_client = NULL;
 9 
10 extern "C" char *redis_hset(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) {
11     try {
12         // 连接Redis
13         if(NULL == m_client) {
14             const char* c_host = getenv("REDIS_HOST");
15             string host = "127.0.0.1";
16             if(c_host) {
17                 host = c_host;
18             }
19             m_client = new redis::client(host);
20         }        
21 
22         if(!(args->args && args->args[0] && args->args[1] && args->args[2])) {
23             *is_null = 1;
24             return result;
25         }
26 
27         // 调用hset插入一个哈希表
28         if(m_client->hset(args->args[0], args->args[1], args->args[2])) {
29             return result;
30         } else {
31             *error = 1;
32             return result;
33         }
34     } catch (const redis::redis_error& e) {
35         return result;
36     }
37 }
38 
39 extern "C" my_bool redis_hset_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
40     if (3 != args->arg_count) {
41         // hset(key, field, value) 需要三个参数
42         strncpy(message, "Please input 3 args for: hset('key', 'field', 'value');", MYSQL_ERRMSG_SIZE);
43         return -1;
44     }
45     if (args->arg_type[0] != STRING_RESULT  || 
46         args->arg_type[1] != STRING_RESULT  || 
47         args->arg_type[2] != STRING_RESULT) { 
48         // 检查参数类型
49         strncpy(message, "Args type error: hset('key', 'field', 'value');", MYSQL_ERRMSG_SIZE);
50         return -1;
51     }
52 
53     args->arg_type[0] = STRING_RESULT;
54     args->arg_type[1] = STRING_RESULT;
55     args->arg_type[2] = STRING_RESULT;
56 
57     initid->ptr = NULL;
58     return 0;
59 }

997755.com澳门葡京 13

编译链接:

[zhxilin@localhost mysql-redis-test]$ g++ -shared -fPIC -I /usr/include/mysql -lboost_serialization -lboost_system -lboost_thread -o libmyredis.so anet.c test.cpp

编写翻译时索要加上-lboost_serialization -lboost_system -lboost_thread,
表示要求链接多个动态库:libboost_serialization.so、libboost_system.so、libboost_thread.so,不然在运维时会报贫乏函数定义的荒谬。

编写翻译出libmyredis.so之后,将其拷贝到mysql的插件目录下并提权:

[root@localhost mysql-redis-test]# cp libmyredis.so /usr/lib64/mysql/plugin/ & chmod 777 /usr/lib64/mysql/plugin/libmyredis.so 

成就今后登陆MySQL,创制关联函数测试一下:

mysql> DROP FUNCTION IF EXISTS `redis_hset`;
Query OK, 0 rows affected (0.16 sec)

mysql> CREATE FUNCTION redis_hset RETURNS STRING SONAME 'libmyredis.so';
Query OK, 0 rows affected (0.02 sec)

先删除老的UDF,注意函数名加反引号(“)。调用UDF测试,再次回到0,推行成功:

997755.com澳门葡京 14

mysql> SELECT redis_hset('zhxilin', 'id', '09388334');
+-----------------------------------------+
| redis_hset('zhxilin', 'id', '09388334') |
+-----------------------------------------+
| 0                                                     |
+-----------------------------------------+
1 row in set (0.00 sec)

997755.com澳门葡京 15

开辟redis-cli,查看结果:

127.0.0.1:6379> HGETALL zhxilin
1) "id"
2) "09388334"

三. 在UDF中访问Redis

跟上述做法未有差距于,只需在UDF里调用Redis提供的接口函数。Redis官方给出了Redis
C++ Client
(https://github.com/mrpi/redis-cplusplus-client),封装了Redis的基本操作。

源码是注重boost,需求先安装boost:

[root@localhost dev]# yum install boost boost-devel

然后下载redis cpp client源码:

[root@localhost dev]# git clone https://github.com/mrpi/redis-cplusplus-client

应用时索要把redisclient.h、anet.h、fmacros.h、anet.c
那6个文件考到目录下,开端编写制定关于Redis的UDF。大家定义了redis_hset作为主函数,连接Redis并调用hset插入哈希表,redis_hset_init作为初阶化,检查参数个数和品种。

997755.com澳门葡京 16

 1 /* test.cpp */
 2 #include <stdio.h>
 3 #include <mysql.h>
 4 #include "redisclient.h"
 5 using namespace boost;
 6 using namespace std;
 7 
 8 static redis::client *m_client = NULL;
 9 
10 extern "C" char *redis_hset(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) {
11     try {
12         // 连接Redis
13         if(NULL == m_client) {
14             const char* c_host = getenv("REDIS_HOST");
15             string host = "127.0.0.1";
16             if(c_host) {
17                 host = c_host;
18             }
19             m_client = new redis::client(host);
20         }        
21 
22         if(!(args->args && args->args[0] && args->args[1] && args->args[2])) {
23             *is_null = 1;
24             return result;
25         }
26 
27         // 调用hset插入一个哈希表
28         if(m_client->hset(args->args[0], args->args[1], args->args[2])) {
29             return result;
30         } else {
31             *error = 1;
32             return result;
33         }
34     } catch (const redis::redis_error& e) {
35         return result;
36     }
37 }
38 
39 extern "C" my_bool redis_hset_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
40     if (3 != args->arg_count) {
41         // hset(key, field, value) 需要三个参数
42         strncpy(message, "Please input 3 args for: hset('key', 'field', 'value');", MYSQL_ERRMSG_SIZE);
43         return -1;
44     }
45     if (args->arg_type[0] != STRING_RESULT  || 
46         args->arg_type[1] != STRING_RESULT  || 
47         args->arg_type[2] != STRING_RESULT) { 
48         // 检查参数类型
49         strncpy(message, "Args type error: hset('key', 'field', 'value');", MYSQL_ERRMSG_SIZE);
50         return -1;
51     }
52 
53     args->arg_type[0] = STRING_RESULT;
54     args->arg_type[1] = STRING_RESULT;
55     args->arg_type[2] = STRING_RESULT;
56 
57     initid->ptr = NULL;
58     return 0;
59 }

997755.com澳门葡京 17

编写翻译链接:

[zhxilin@localhost mysql-redis-test]$ g++ -shared -fPIC -I /usr/include/mysql -lboost_serialization -lboost_system -lboost_thread -o libmyredis.so anet.c test.cpp

编写翻译时须求加上-lboost_serialization -lboost_system -lboost_thread,
表示需求链接两个动态库:libboost_serialization.so、libboost_system.so、libboost_thread.so,不然在运转时会报贫乏函数定义的百无一是。

编写翻译出libmyredis.so之后,将其拷贝到mysql的插件目录下并提权:

[root@localhost mysql-redis-test]# cp libmyredis.so /usr/lib64/mysql/plugin/ & chmod 777 /usr/lib64/mysql/plugin/libmyredis.so 

形成之后登入MySQL,创制关联函数测试一下:

mysql> DROP FUNCTION IF EXISTS `redis_hset`;
Query OK, 0 rows affected (0.16 sec)

mysql> CREATE FUNCTION redis_hset RETURNS STRING SONAME 'libmyredis.so';
Query OK, 0 rows affected (0.02 sec)

先删除老的UDF,注意函数名加反引号(“)。调用UDF测试,再次来到0,实施成功:

997755.com澳门葡京 18

mysql> SELECT redis_hset('zhxilin', 'id', '09388334');
+-----------------------------------------+
| redis_hset('zhxilin', 'id', '09388334') |
+-----------------------------------------+
| 0                                                     |
+-----------------------------------------+
1 row in set (0.00 sec)

997755.com澳门葡京 19

展开redis-cli,查看结果:

127.0.0.1:6379> HGETALL zhxilin
1) "id"
2) "09388334"

4. 通过MySQL触发器刷新Redis

 在上一节的底子上,大家想让MySQL在增加和删除改查的时候自动调用UDF,还须要正视MySQL触发器。触发器能够监听INSERT、UPDATE、DELETE等基本操作。在MySQL中,成立触发器的基本语法如下:

CREATE TRIGGER trigger_name
trigger_time
trigger_event ON table_name
FOR EACH ROW
trigger_statement

trigger_time代表触发时机,值为AFTERBEFORE

trigger_event代表触发的轩然大波,值为INSERTUPDATEDELETE等;

trigger_statement表示触发器的程序体,能够是一句SQL语句可能调用UDF。

在trigger_statement中,假诺有多条SQL语句,要求用BEGIN…END包涵起来:

BEGIN
[statement_list]
END

鉴于MySQL暗中认可的终止分隔符是分号(;),假如大家在BEGIN…END中冒出了分店,将被标志成终结,此时无法完成触发器的定义。有贰个方式,能够调用DELIMITE昂Cora命令来目前修改达成分隔符,用完再改会分号就可以。举个例子改成$:

mysql> DELIMITER $

我们初叶定义贰个触发器,监听对Student表的插入操作,Student表在上一篇文章中开创的,能够查阅上一篇文章。

mysql > DELIMITER $
      > CREATE TRIGGER tg_student 
      > AFTER INSERT on Student 
      > FOR EACH ROW 
      > BEGIN
      > SET @id = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'id', CAST(new.Sid AS CHAR(8))));
      > SET @name = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'name', CAST(new.Sname AS CHAR(20))));
      > Set @age = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'age', CAST(new.Sage AS CHAR))); 
      > Set @gender = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'gender', CAST(new.Sgen AS CHAR))); 
      > Set @dept = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'department', CAST(new.Sdept AS CHAR(10))));    
      > END $

创办完触发器可以由此show查看,大概drop删除:

mysql> SHOW TRIGGERS;

mysql> DROP TRIGGER tg_student;

接下去大家调用一句插入语句,然后观察Redis和MySQL数据的调换:

mysql> INSERT INTO Student VALUES('09388165', 'Rose', 19, 'F', 'SS3-205');
Query OK, 1 row affected (0.27 sec)

MySQL的结果:

mysql> SELECT * FROM Student;
+----------+---------+------+------+---------+
| Sid      | Sname   | Sage | Sgen | Sdept   |
+----------+---------+------+------+---------+
| 09388123 | Lucy    |   18 | F    | AS2-123 |
| 09388165 | Rose    |   19 | F    | SS3-205 |
| 09388308 | zhsuiy  |   19 | F    | MD8-208 |
| 09388318 | daemon  |   18 | M    | ZS4-630 |
| 09388321 | David   |   20 | M    | ZS4-731 |
| 09388334 | zhxilin |   20 | M    | ZS4-722 |
+----------+---------+------+------+---------+
6 rows in set (0.00 sec)

Redis的结果:

127.0.0.1:6379> HGETALL stu_09388165
 1) "id"
 2) "09388165"
 3) "name"
 4) "Rose"
 5) "age"
 6) "19"
 7) "gender"
 8) "F"
 9) "department"
10) "SS3-205"

以上结果注脚,当MySQL插入数据时,通过触发器调用UDF,实现了全自动刷新Redis的数据。别的,调用MySQL插入的下令,能够透过C++完成,进而就落到实处了在C++的作业逻辑里,只需调用MySQL++的接口就会达成MySQL数据库和Redis缓存的翻新,那有个别剧情在上壹篇作品已经介绍过了。

 

4. 通过MySQL触发器刷新Redis

 在上一节的基础上,大家想让MySQL在增删改查的时候自动调用UDF,还亟需借助MySQL触发器。触发器能够监听INSERT、UPDATE、DELETE等基本操作。在MySQL中,成立触发器的主导语法如下:

CREATE TRIGGER trigger_name
trigger_time
trigger_event ON table_name
FOR EACH ROW
trigger_statement

trigger_time表示触发时机,值为AFTERBEFORE

trigger_event表示触发的事件,值为INSERTUPDATEDELETE等;

trigger_statement表示触发器的程序体,能够是一句SQL语句大概调用UDF。

在trigger_statement中,纵然有多条SQL语句,供给用BEGIN…END包蕴起来:

BEGIN
[statement_list]
END

是因为MySQL私下认可的截止分隔符是分号(;),要是我们在BEGIN…END中冒出了总部,将被标识成终结,此时无法完毕触发器的定义。有二个措施,可以调用DELIMITEEnclave命令来临时修改完结分隔符,用完再改会分号就可以。比如改成$:

mysql> DELIMITER $

大家早先定义3个触发器,监听对Student表的插入操作,Student表在上壹篇文章中开创的,能够查看上一篇文章。

997755.com澳门葡京 20

mysql > DELIMITER $
      > CREATE TRIGGER tg_student 
      > AFTER INSERT on Student 
      > FOR EACH ROW 
      > BEGIN
      > SET @id = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'id', CAST(new.Sid AS CHAR(8))));
      > SET @name = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'name', CAST(new.Sname AS CHAR(20))));
      > Set @age = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'age', CAST(new.Sage AS CHAR))); 
      > Set @gender = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'gender', CAST(new.Sgen AS CHAR))); 
      > Set @dept = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'department', CAST(new.Sdept AS CHAR(10))));    
      > END $

997755.com澳门葡京 21

997755.com澳门葡京,创造完触发器能够经过show查看,或许drop删除:

mysql> SHOW TRIGGERS;

mysql> DROP TRIGGER tg_student;

接下去我们调用一句插入语句,然后旁观Redis和MySQL数据的扭转:

mysql> INSERT INTO Student VALUES('09388165', 'Rose', 19, 'F', 'SS3-205');
Query OK, 1 row affected (0.27 sec)

MySQL的结果:

997755.com澳门葡京 22

mysql> SELECT * FROM Student;
+----------+---------+------+------+---------+
| Sid      | Sname   | Sage | Sgen | Sdept   |
+----------+---------+------+------+---------+
| 09388123 | Lucy    |   18 | F    | AS2-123 |
| 09388165 | Rose    |   19 | F    | SS3-205 |
| 09388308 | zhsuiy  |   19 | F    | MD8-208 |
| 09388318 | daemon  |   18 | M    | ZS4-630 |
| 09388321 | David   |   20 | M    | ZS4-731 |
| 09388334 | zhxilin |   20 | M    | ZS4-722 |
+----------+---------+------+------+---------+
6 rows in set (0.00 sec)

997755.com澳门葡京 23

Redis的结果:

997755.com澳门葡京 24

127.0.0.1:6379> HGETALL stu_09388165
 1) "id"
 2) "09388165"
 3) "name"
 4) "Rose"
 5) "age"
 6) "19"
 7) "gender"
 8) "F"
 9) "department"
10) "SS3-205"

997755.com澳门葡京 25

如上结果评释,当MySQL插入数据时,通过触发器调用UDF,达成了电动刷新Redis的数码。其它,调用MySQL插入的通令,可以经过C++完成,进而就贯彻了在C++的事情逻辑里,只需调用MySQL++的接口就能够促成MySQL数据库和Redis缓存的换代,那部分内容在上壹篇文章早已介绍过了。

 

4. 通过MySQL触发器刷新Redis

 在上一节的根底上,大家想让MySQL在增加和删除改查的时候自动调用UDF,还须要重视MySQL触发器。触发器能够监听INSERT、UPDATE、DELETE等基本操作。在MySQL中,创设触发器的骨干语法如下:

CREATE TRIGGER trigger_name
trigger_time
trigger_event ON table_name
FOR EACH ROW
trigger_statement

trigger_time表示触发时机,值为AFTERBEFORE

trigger_event表示触发的风云,值为INSERTUPDATEDELETE等;

trigger_statement代表触发器的程序体,能够是一句SQL语句或然调用UDF。

在trigger_statement中,倘诺有多条SQL语句,要求用BEGIN…END包括起来:

BEGIN
[statement_list]
END

出于MySQL暗中同意的甘休分隔符是分号(;),假诺我们在BEGIN…END中冒出了分店,将被标识成终结,此时没法做到触发器的概念。有三个办法,可以调用DELIMITELAND命令来暂且修改达成分隔符,用完再改会分号就能够。比方改成$:

mysql> DELIMITER $

笔者们初步定义一个触发器,监听对Student表的插入操作,Student表在上一篇文章中开创的,可以查看上一篇文章。

997755.com澳门葡京 26

mysql > DELIMITER $
      > CREATE TRIGGER tg_student 
      > AFTER INSERT on Student 
      > FOR EACH ROW 
      > BEGIN
      > SET @id = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'id', CAST(new.Sid AS CHAR(8))));
      > SET @name = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'name', CAST(new.Sname AS CHAR(20))));
      > Set @age = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'age', CAST(new.Sage AS CHAR))); 
      > Set @gender = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'gender', CAST(new.Sgen AS CHAR))); 
      > Set @dept = (SELECT redis_hset(CONCAT('stu_', new.Sid), 'department', CAST(new.Sdept AS CHAR(10))));    
      > END $

997755.com澳门葡京 27

创设完触发器能够因而show查看,或许drop删除:

mysql> SHOW TRIGGERS;

mysql> DROP TRIGGER tg_student;

接下去大家调用一句插入语句,然后观看Redis和MySQL数据的变化:

mysql> INSERT INTO Student VALUES('09388165', 'Rose', 19, 'F', 'SS3-205');
Query OK, 1 row affected (0.27 sec)

MySQL的结果:

997755.com澳门葡京 28

mysql> SELECT * FROM Student;
+----------+---------+------+------+---------+
| Sid      | Sname   | Sage | Sgen | Sdept   |
+----------+---------+------+------+---------+
| 09388123 | Lucy    |   18 | F    | AS2-123 |
| 09388165 | Rose    |   19 | F    | SS3-205 |
| 09388308 | zhsuiy  |   19 | F    | MD8-208 |
| 09388318 | daemon  |   18 | M    | ZS4-630 |
| 09388321 | David   |   20 | M    | ZS4-731 |
| 09388334 | zhxilin |   20 | M    | ZS4-722 |
+----------+---------+------+------+---------+
6 rows in set (0.00 sec)

997755.com澳门葡京 29

Redis的结果:

997755.com澳门葡京 30

127.0.0.1:6379> HGETALL stu_09388165
 1) "id"
 2) "09388165"
 3) "name"
 4) "Rose"
 5) "age"
 6) "19"
 7) "gender"
 8) "F"
 9) "department"
10) "SS3-205"

997755.com澳门葡京 31

上述结果表明,当MySQL插入数据时,通过触发器调用UDF,完成了机关刷新Redis的多少。此外,调用MySQL插入的授命,能够因而C++达成,进而就得以完成了在C++的政工逻辑里,只需调用MySQL++的接口就能够兑现MySQL数据库和Redis缓存的翻新,那有个别剧情在上一篇文章一度介绍过了。

 

总结

通过实施,能体味到MySQL和Redis是多么亲切相爱呢!^_^

本篇小说讲了从最基础的UDF开始,再到通过UDF连接Redis插入数据,再进一步介绍通过MySQL
Trigger自动更新Redis数据的全体思路,落成了2个目的,即只在作业代码中更新MySQL数据库,进而Redis能够自动同步刷新。

MySQL对UDF函数和触发器的辅助,使得完成Redis数据和MySQL自动同步成了说不定。当然UDF究竟是通过插件的花样运营在MySQL中的,并从未过多的吴忠干预,一旦插件发生致命性崩溃,有希望MySQL也会挂,所以在编排UDF的时候必要极度谨慎!

 

总结

由此实行,能体味到MySQL和Redis是多么亲切相爱吗!^_^

本篇文章讲了从最基础的UDF初叶,再到通过UDF连接Redis插入数据,再进一步介绍通过MySQL
Trigger自动更新Redis数据的成套思路,落成了3个目标,即只在事情代码中更新MySQL数据库,进而Redis能够自行同步刷新。

MySQL对UDF函数和触发器的协理,使得落成Redis数据和MySQL自动同步成了说不定。当然UDF究竟是通过插件的格局运行在MySQL中的,并从未过多的广安干预,一旦插件发生致命性崩溃,有望MySQL也会挂,所以在编制UDF的时候要求足够小心翼翼!

 

如上内容来自:

总结

通过举办,能体味到MySQL和Redis是何等亲切相爱呢!^_^

本篇文章讲了从最基础的UDF起初,再到通过UDF连接Redis插入数据,再进一步介绍通过MySQL
Trigger自动更新Redis数据的总体思路,达成了四个对象,即只在工作代码中创新MySQL数据库,进而Redis能够自动同步刷新。

MySQL对UDF函数和触发器的支撑,使得落成Redis数据和MySQL自动同步成了大概。当然UDF毕竟是经过插件的情势运维在MySQL中的,并未过多的安全干预,1旦插件产生致命性崩溃,有非常的大希望MySQL也会挂,所以在编排UDF的时候须求丰盛如临深渊!

 

上述内容出自:

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website