在服务端开发过程中,一般会使用MySQL等关系型数据库作为最终的存储引擎,Redis其实也可以作为一种键值对型的数据库,但在一些实际场景中,特别是关系型结构并不适合使用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去完成。
一. 什么是UDFUDF,是User Defined Function的缩写,用户定义函数。MySQL支持函数,也支持自定义的函数。UDF比存储方法有更高的执行效率,并且支持聚集函数。
UDF定义了5个API:xxx_init()、xxx_deinit()、xxx()、xxx_add()、xxx_clear()。官方文档()给出了这些API的说明。相关的结构体定义在mysql_com.h里,它又被mysql.h包含,使用时只需#include<mysql.h>即可。他们之间的关系和执行顺序可以以下图来表示:
1. xxx()这是主函数,5个函数至少需要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++ TypeSTRING char *
INTEGER long long
REAL double
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);
4. xxx_add()在聚合UDF中反复调用,将参数加入聚合参数中。函数的声明如下:
void xxx_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null,char *error);
5. xxx_clear()在聚合UDF中反复调用,重置聚合参数,为下一行数据的操作做准备。函数的声明如下:
void xxx_clear(UDF_INIT *initid, char *is_null, char *error);
二. UDF函数的基本使用在此之前,需要先安装mysql的开发包:
[root@localhost zhxilin]# yum install mysql-devel -y