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

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 墓碑线 墓碑节杖 墓碑碑文 贤者墓碑 梦到墓碑 戾者墓碑 马克思墓碑 血战墓碑镇 怨者墓碑 墓碑镇 陵园墓碑 墓碑文字 墓碑图 墓碑书 墓碑多少钱 墓碑价格表 墓碑厂家 墓碑 价格 墓碑石 墓碑定制 刻墓碑 墓碑内容 墓碑的样式 墓碑鲜花 半截墓碑 怎样写墓碑 墓碑石钉头 墓碑文化 k线墓碑线 墓碑文 抄墓碑 墓碑网站 墓碑的形状 墓碑公司 墓碑怎么写 国外墓碑 墓碑样式 墓碑铭 蓝洁瑛墓碑被熏黑 墓碑碑文范例 父母墓碑碑文范例