C扩展Hiredis调用Redis并整合到MySQL插件中
来源:互联网 发布:linux 设置命令别名 编辑:程序博客网 时间:2024/06/06 00:05
一、使用C/C++为Mysql开发扩展函数
1、安装mysql开发包:mysql-devel
sudo apt-get install libmysqld-dev # ubuntuyum install mysql-devel # centos
默认安装在 /usr/include/mysql/ 中,包含了 mysql 插件开发所需的头文件
2、最简单的扩展函数
#include <stdio.h>#include "mysql.h"extern "C" long long 函数名(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) { // return ....} // 初始化函数extern "C" my_bool 函数名_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { return 0;}
程序返回类型和 mysql 对应:
Varchar <-> char *INTEGER <-> long longREAL <-> double
3、编译(使用g++)
g++ -I /usr/include/mysql/ -shared -fPIC -o xxx.so xxx.cpp
-I 代表 include的头文件的位置
4、插件部署
cp xxx.so /usr/lib/mysql/plugin/
5、在 Mysql 中创建函数
CREATE FUNCTION 函数名 RETURNS 返回值 SONAME 'xxx.so';
若想删除,可以使用 Drop function 函数名;
二、使用C/C++扩展Hiredis和Redis交互
1、下载编译 Hiredis
git clone https://github.com/redis/hiredis.git
然后进入 Hiredis 目录:
makesudo make install # 把动态链接库拷贝到/usr/local/lib/中
2、编码
https://github.com/redis/hiredis 中有 Hiredis 的详细使用说明
#include <stdio.h>#include <hiredis/hiredis.h>int main(){ redisContext *c = redisConnect("127.0.0.1", 6379); if (c == NULL || c->err) { if (c) { printf("Error: %s\n", c->errstr); // handle error } else { printf("Can't allocate redis context\n"); }}redisCommand(c, "redis指令");redisFree(c);return 0;}
3、编译
g++ -L /usr/local/lib/ -l hiredis -o xxx xxx.c
-L 代表库文件的位置
-l 代表扩展名称
4、执行
./xxx
三、整合(用sql操作redis)
1、用C/C++封装方法(如 hset方法 和 hget方法)
#include <stdio.h>#include <string.h>#include <string>#include "mysql.h"#include <hiredis/hiredis.h>using namespace std; const char *redisHost="127.0.0.1"; int redisPort=6379;extern "C" long long hset(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) { redisContext* c = redisConnect(redisHost, redisPort); char *tabName = (char *)args->args[0]; char *keyField = (char *)args->args[1]; char *valueField =(char *)args->args[2]; if ( c->err) { redisFree(c); strcpy(error,"connect error"); return -1; } redisReply* r = (redisReply*)redisCommand(c, " hset %s %s %s",tabName,keyField,valueField); freeReplyObject(r); //free redis command redisFree(c); //free redis connect return 1;} extern "C" my_bool hset_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { if(args->arg_count!=3){ strcpy( message , "Expected exactly three arguments" ); return 1; } return 0;} extern "C" char *hget(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) { redisContext* c = redisConnect(redisHost, redisPort); char *tabName = (char *)args->args[0]; char *keyField = (char *)args->args[1]; if ( c->err) { redisFree(c); strcpy(error,"connect error"); return NULL; } redisReply* r = (redisReply*)redisCommand(c, " hget %s %s ",tabName,keyField); if ( r->type != REDIS_REPLY_STRING) { freeReplyObject(r); redisFree(c); return NULL; } string getStr=r->str; char *getResult=const_cast<char*>(getStr.c_str()); // strcpy(getResult,getStr.c_str()); freeReplyObject(r); //free redis command redisFree(c); //free redis connect return getResult;} extern "C" my_bool hget_init(UDF_INIT *initid, UDF_ARGS *args, char *message) { if(args->arg_count!=2){ strcpy( message , "hget needs tablename and keyfield" ); return 1; } return 0;}
2、编译
g++ -I /usr/include/mysql/ -L /usr/local/lib/ -l hiredis -shared -fPIC -o xxx.so xxx.cpp
-fPIC 代表编译后位置独立
-shared 代表生成的是动态链接库
3、插件部署
cp xxx.so /usr/lib/mysql/plugin/
4、在 Mysql 中创建函数
CREATE FUNCTION hget RETURNS STRING SONAME 'xxxx.so';CREATE FUNCTION hset RETURNS STRING SONAME 'xxxx.so';
5、Mysql 操作 Redis
select hset('test','1','jack');select hget('test','1');
#可能遇到的问题
1、undefined symbol: freeReplyObject
不清楚什么原因,个人解决方法:删除.so文件并重新编译,编译时将 -shared -fPIC -o 参数移至最前面
g++ -shared -fPIC -o xxx.so xxx.cpp -I /usr/include/mysql/ -L /usr/local/lib/ -l hiredis
2、No such file or directory
原因一般有两个:
一个是操作系统里确实没有包含该共享库(lib*.so.*文件)或者共享库版本不对, 遇到这种情况那就去网上下载并安装上即可;
另外一个原因就是已经安装了该共享库, 但执行需要调用该共享库的程序的时候, 程序按照默认共享库路径找不到该共享库文件。
解决方法有两个:
1)、把/usr/local/lib加入到共享库配置文件/etc/ld.so.conf中(可能无效):
echo "/usr/local/lib" >> /etc/ld.so.confldconfig
2)、把 /usr/local/lib/libhiredis.so.0.13 文件复制到 /usr/lib/ 中
sudo cp /usr/local/lib/libhiredis.so.0.13 /usr/lib/
3. 乱码和‘Lost connection to MySQL server during query’
hset() 可以操作成功,但是会报错
hget() 会读取到乱码,不知道是什么原因导致的…
不过在 redis-cli 客户端和 PHP 程序中读取数据一切OK
参考:
http://blog.csdn.net/chinalinuxzend/article/details/4236354
http://blog.chinaunix.net/uid-26212859-id-3256667.html