引言

关于Mysql,大家都已经非常熟悉了。但是这种C/S的数据服务不适合于一些轻量级的应用,很多情况下,我们希望能使用一个进程级的存储引擎,供我们查询一些关系数据,而非使用一套臃肿的服务。当然这时我们可以选择SqlLite,Berkeley DB,Access等轻量级的存储件,但是都有学习成本,我们能否采用我们已经非常熟悉的Mysql接口来实现呢?答案是肯定的,很多人可能不知道:Mysql其实可以将服务以library的形式编译,供程序单独使用,这样我们的程序相当于内联了一套Mysql服务。

编译

我们以linux下的编译为例介绍编译Embedded Mysql的步骤。

Mysql 5.0版本的编译

在Mysql 5.0及之前版本,都是采用autobuild工具编译,config时的参数可以如下配置:

./configure --prefix=/home/work/mysql --with-embedded-server--with-mysqld-ldflags--with-mysqld-ldflags=-all-static--enable-thread-safe-client --enable-local-infile

--with-extra-charsets=complex--disable-shared

上面的参数中:

--prefix=/home/work/mysql 指定安装位置,可以根据自己的需要设置到其他目录。

--with-embedded-server是编译embedded mysql的关键,这个参数默认是不开启的,因此一般只会编译出libmysqlclient.a(.so)这个客户端API库,而开启此参数后,会多生成一个libmysqld.a(.so)的库,这个库同时集成了mysql服务与客户端API。

--with-mysqld-ldflags=-all-static与--disable-shared两个参数表示只编译静态库,如果需要使用动态库,也可以去掉这两个参数。

-enable-thread-safe-client表示客户端API应该保持线程安全(但貌似Mysql 5.0有bug,即使开启此参数,有时也非线程安全)。

--with-extra-charsets=complex 表示支持大字符集。

configure完成之后:

$ make

$ make install

即可以完成编译。

Mysql 5.5之后的版本编译

mysql 5.5之后的版本都迁移到采用cmake进行编译,因此机器需要先安装cmake,关于cmake的安装,在此不做介绍,可以参考:

安装cmake之后,可以用下面的命令编译

cmake .   -DWITH_EMBEDDED_SERVER=1 -DCMAKE_INSTALL_PREFIX=/home/work/mysql  -DCMAKE_BUILD_TYPE=Release

上面的参数中:

-DCMAKE_INSTALL_PREFIX指定安装位置,与5.0中的--prefix对应。

-DDWITH_EMBEDDED_SERVER表示将编译Embedded Mysql库,与5.0中的--with-embedded-server对应。

-DCMAKE_BUILD_TYPE表示生成库的方式,它有以下几种选项:

1. RelWithDebInfo 带调试信息,开启编译优化的库,编译参数为-O2 -g

2. Debug 带调试信息,不做任何编译优化的库,编译参数-g

3. Release 不带调试信息,编译优化的库,编译参数-O2

4. MinSizeRel 不带调试信息,最小size的库,编译参数-Os

Mysql5.5之后的版本编出的库都是线程安全的,所以不需要 类似-enable-thread-safe-client的参数

是否带调试信息对生成出库的大小影响很大,例如Debug库编译出来有70多兆,而Release编译出来只有不到20MB,如果不需要调试,建议已Release编译。

Embedded Mysql使用方法

我们编写如下代码(test.cpp)进行测试:

#include

#include

#include

#include

int main()

{

MYSQL* sql;

MYSQL_STMT* stmt;

MYSQL_BIND bind;

unsigned* indice;

int ret;

int result;

unsigned long length;

char query1[] = "create database if not exists mydb";

char query2[] = "use mydb";

char query3[] = "create table if not exists mytable (id int not null, col int not

null)";

char query4[] = "insert into mytable (id, col) values (1,100)";

char query5[] = "select col from mytable where id = ?";

char *server_options[] = { "","--defaults-file=my.cnf","--basedir=./"};

int num_elements = sizeof(server_options)/ sizeof(char *);

if(mysql_server_init(num_elements, server_options, NULL))

{

puts("failed to initialize server");

return 1;

}

sql = mysql_init(NULL);

if(!mysql_real_connect(sql, NULL , NULL , NULL , NULL, 3306, NULL, 0))

printf("failed to connect\n");

if(mysql_query(sql, query1))

printf("failed to create database:%s\n", mysql_error(sql));

ret = mysql_query(sql, query2);

if(ret)

printf("failed to use database:%s\n", mysql_error(sql));

ret = mysql_query(sql, query3);

if(ret)

printf("failed to create table:%s\n", mysql_error(sql));

ret = mysql_query(sql, query4);

if(ret)

printf("failed to insert record:%s\n", mysql_error(sql));

stmt = mysql_stmt_init(sql);

if(!stmt)

printf("failed to init stmt:%s\n", mysql_error(sql));

ret = mysql_stmt_prepare(stmt, query5, strlen(query5));

if(ret)

printf("failed to prepare:%s\n", mysql_stmt_error(stmt));

result = 1;

memset(&bind, 0 , sizeof(bind));

bind.buffer_type = MYSQL_TYPE_LONG;

bind.is_unsigned = (my_bool)0;

bind.is_null = 0;

bind.buffer = (char*)&result;

bind.buffer_length = 4;

bind.length = &length;

ret = mysql_stmt_bind_param(stmt, &bind);

if(ret)

printf("failed to bind param:%s\n", mysql_stmt_error(stmt));

ret = mysql_stmt_execute(stmt);

if(ret)

printf("failed to execute stmt:%s\n", mysql_stmt_error(stmt));

memset(&bind, 0 , sizeof(bind));

bind.buffer_type = MYSQL_TYPE_LONG;

bind.is_unsigned = (my_bool)0;

bind.is_null = 0;

bind.buffer = (char*)&result;

bind.buffer_length = 4;

bind.length = &length;

ret = mysql_stmt_bind_result(stmt, &bind);

if(ret)

printf("failed to bind result:%s\n", mysql_stmt_error(stmt));

ret = mysql_stmt_store_result(stmt);

if(ret)

printf("failed to store result:%s\n", mysql_stmt_error(stmt));

ret = mysql_stmt_fetch(stmt);

if(ret)

printf("failed to fetch result:%s\n", mysql_stmt_error(stmt));

mysql_stmt_close(stmt);

mysql_close(sql);

mysql_server_end();

return 0;

}

从代码我们可以看出,使用embedded mysql的方法与使用一般的mysql API基本一致,但是需要在使用前后初始化库与清理环境,分别调用mysql_server_init()与mysql_server_end()这两个函数。其中,mysql_server_init中可以指定mysql服务的配置文件my.cnf以及数据生成的位置(也可以不在init中配置数据目录,在my.cnf文件中配置数据目录)。

相比正式的mysql服务,embedded mysql的my.cnf只支持[server]与[embedded]这两节配置,我们可以在当前目录下创建一个类似下面的my.cnf:

[server]

language=/home/work/mysql/share/english

datadir==./data

[embedded]

language==/home/work/mysql/share/english

注意:上面的配置文件中,datadir指定mysql数据保存的位置(注意:该目录必须在程序启动前已存在,如果不存在需要提前手工创建,否则会启动失败)。language这个选项相当重要,它指定的是服务端与客户端各种错误信息的资源文件。我们可以在mysql安装目录的share目录下找到多种语言的资源文件,一般采用share/english/errmsg.sys即可(既可以直接将language指向这个目录,也可以将这个文件拷贝至当前目录下,然后将language指向目录设为./)。

配置好my.cnf之后,我们如下编译:

$ g++ test.cpp -o a.out  -I/home/work/mysql/include -L/home/work/mysql/lib -lmysqld

如果编译了动态链接库,生成的执行文件可能不能正常运行,需要在LD_LIBRARY_PATH中导出libmysqld.so的位置:

$ export  LD_LIBRARY_PATH=/home/work/mysql/lib:$LD_LIBRARY_PATH

编译生成a.out,执行即可查询。

注意事项

embedded mysql目前只能使用inno-db引擎,它会在datadir指定的目录下生成数据库文件,每个database用一个目录保存,我们也可以将这些数据库目录拷贝到真正的mysql服务的数据目录中,使用mysql工具进行查询(注意:如果这么操作,mysql服务必须重启)。

关于Mysql 5.5的bug

本节是我在使用embedded mysql过程中发现的一些bug,这些bug至少在Mysql 5.5.15版本中存在,我已向Mysql社区反映,在官方修复之前,建议在编译之前修改下面一些文件:

bug1:会导致多线程下的内存泄漏

在libmysqld/lib_sql.cc源代码的256行:

stmt->fields= mysql->fields;

之后添加:

free_root(&stmt->mem_root, MYF(0));

bug2:会导致多线程下的内存泄漏

在libmysqld/lib_sql.cc的356行(stmt->result= *data;语句之前)加:

if(stmt->result.alloc.free != (*data).alloc.free ||

stmt->result.alloc.pre_alloc != (*data).alloc.pre_alloc)

{

free_root(&stmt->result.alloc, MYF(0));

}

bug3:会导致某些查询失败

在libmysqld/lib_sql.cc的346行:

if (res)

{

NET *net= &stmt->mysql->net;

set_stmt_errmsg(stmt, net);

DBUG_RETURN(1);

}

之后,添加下面两行代码:

else if (stmt->mysql->status==MYSQL_STATUS_GET_RESULT)

stmt->mysql->status= MYSQL_STATUS_STATEMENT_GET_RESULT;

结论

使用Embedded Mysql方案可以尽可能少的改动我们的代码,兼容Mysql服务,实现轻量级的关系数据库存储。

其他

mysql embeded 用法_Embedded Mysql | 学步园相关推荐

  1. 安装mysql 10055_Can’t connect to MySQL server on ‘localhost’ (10055) | 学步园

    服务器:   windows2000   server   +   iis5.0   +   php   isapi   +   mysql 我用php+mysql开发了一个web站,该站访问量很高. ...

  2. 如何设置mysql的运行目录_如何修改mysql数据库文件的路径 | 学步园

    在网上找了好多,没有确定哪个是最终的答案,由于网站在运行中,实在不敢轻易动手,怎么奈我是个菜鸟呢!先把找到的东西简单记录一下,回头再说! 还有一个: 首先在数据库里看一下数据库里当前数据文件的存放路径 ...

  3. mysql ping 长连接超时时间_mysql_ping与mysql长连接(部分摘录) | 学步园

    mysql_ping与mysql长连接 今天有大收获.最近开发的一个系统,后台用的线程池来处理请求,而每个线程池持有一个mysql连接.这个程序有时候会莫名其妙的死掉,好像是在操作数据库的时候.由于出 ...

  4. mysql json_extract用法,【MySQL】json_extract解析json

    MySQL5.7 json串如下: {"Data":{"List":[{"ID":"101010","NAME ...

  5. android+mysql+server+error_Lost connection to MySQL server during query错误 | 学步园

    关于 Lost connection to MySQL server during query 错误2007年04月11日 星期三 00:56晚上在虚拟机上继续玩 Delphi for PHP,想试试 ...

  6. error lnk2001: mysql_使用mysql时的链接错误 | 学步园

    当使用mysql时出现错误: mysqlclient.lib(inftrees.obj) : error LNK2001: unresolved external symbol ___security ...

  7. Hive mysql 内连接_Hive-表连接 | 学步园

    Hive只支持等值连接,即ON子句中使用等号连接,不支持非等值连接. Hive内置的数据存储类型,TextFile, SequenceFile, ORC(列式存储) 如果连接语句中有WHERE子句,会 ...

  8. mysql修行练级之mysql新手入门常用命令

    mysql修行练级之mysql新手入门常用命令 创建时间:2014.08.24 修改时间:2014.09.26 从一个运维工程师和DBA新手的角度出发,学习,实践从而掌握mysql相关操作. 1.登录 ...

  9. mysql 异常关机后 无法查数据_MySQL数据库非法关机造成数据表损坏怎么排查 | 学步园...

    该篇文章我们介绍由于非法硬件关机,造成了MySQL数据库的数据表损坏,数据库不能正常运行的一个实例.下面学步园小编来讲解下MySQL数据库非法关机造成数据表损坏怎么排查? MySQL数据库非法关机造成 ...

  10. mysql超长sql查询_超长SQL怎么查询?MySQL列长度限制有哪些 | 学步园

    MySQL字符串的限制长度看似重要性不要,其实和整个MySQL数据库的安全性是息息相关的,很值得我们去深入研究分析.SQL注入攻击一直都在被广泛的讨论,然而人们却忽略了今天我将要介绍的这两个安全隐患, ...

最新文章

  1. 一些可运行的C语言数据结构代码
  2. mysql里面的sql_mysql工作中的sql
  3. python学习-模块和包
  4. 漫画:如何用栈实现队列
  5. springboot 注解动态赋值_SpringBoot 使用 @Value 注解读取配置文件给静态变量赋值
  6. 事务java_Java事务之一——Java事务的基本问题
  7. 部署一个Windows Server 2008 的只读域控制器
  8. 经验之谈:内存问题造成数据库性能异常怎么破?
  9. Go语言学习Day06
  10. using namespace std;的陷阱
  11. 《几何与代数导引》习题1.34.2
  12. 用这些进行PDF翻译,双语对照、翻译后排版不变、还免费!
  13. 高考前最后一天,AI 监考老师已就位
  14. SpringBoot水果商城后台管理系统(文末附源码)
  15. 移动化之后,BAT下一步走向何方?我们又该走向何方?
  16. 拆轮子之Fish动画分析
  17. 电脑专业英语1695词
  18. 干货:一个案例看懂“结巴”分词(Jieba),入行NLP必备
  19. 智能风控模型之数据源类型
  20. 编译程序和解释程序有什么区别?

热门文章

  1. C++校内模拟赛-06水题
  2. NTP网络校时(北斗卫星授时设备)技术核心源码让网络时间同步不再难
  3. 快速爬取腾讯招聘信息
  4. PuTTY key format too new怎么解决?
  5. 批量导出Outlook所有联系人到vcard文件
  6. mysql strtolower_自己写的mysql类_PHP教程 - strtolower
  7. bzoj 4987: Tree 树形dp
  8. Elasticsearch08:es-ik添加自定义词库、热更新词库
  9. MacPro安装运行Win10虚拟机 (Parallels Desktop)
  10. 谷歌(chrome)浏览器扩展程序