最初的想法是,rabbitmq 客户端从 queue 消费到了包含 sql 语句的消息后,需要提取并分析该 sql 后,通过 MySQL 协议再要求数据库执行该 sql 语句。这就要求我这个 demo 必须实现了 MySQL 客户端侧所需的协议部分。要实现这个,有三种途径:
不打算用公司的 dbi 库,首先,该库基于了其他的公司库,而我并不想使用;其次,该库封装的也不是很好,之前我还查出了 4 处崩溃,不排除还有其他问题;最后,该库其实也是在 mysqlclient 上做的封装,和上面第 2条其实是一样的。所以,最终我决定选择第 2 种方式,自己搞个“山头”出来。
PS:其实开始的时候也想过采用上面的第 3 种方式,自己从底层开始实现如何支持 MySQL 客户端协议,结果“呵呵”了,难度和工作量不是一般的大~~
确定基于什么来做开发后,该做下一步目标选择了:
可以参考的客户端实现(似乎)有:
4.5. MySQL Client Programs
4.5.1. mysql — The MySQL Command-Line Tool
4.5.2. mysqladmin — Client for Administering a MySQL Server
4.5.3. mysqlcheck — A Table Maintenance Program
4.5.4. mysqldump — A Database Backup Program
4.5.5. mysqlimport — A Data Import Program
4.5.6. mysqlshow — Display Database, Table, and Column Information
4.5.7. mysqlslap — Load Emulation Client
其中 mysql、mysqladmin、mysqlshow 和 mysqlslap 看起来很值得研究。 于是开始研究如何在 Linux下用 C 语言 API 连接 MySQL 数据库。
在 MySQL 官网上找到了如下内容,对基于 MySQL C API 实现客户端应用程序的说明(个人总结)
================================
22.8.1. MySQL C API Implementations
MySQL C API 为客户端应用程序提供了用于和 MySQL server 通信使用的基于 C 的 API。
提供了两种版本的库供使用:libmysqlclient(客户端版本)和 libmysqld(嵌入式服务器版本)。
在 Unix (以及 Unix-like)系统上,静态库为 libmysqlclient.a,动态库为 libmysqlclient.so 。
带 _r 后缀的库的含义:在 MySQL 5.5 以前,带 _r 后缀的库为 thread-safe (re-entrant) 的库,否则,则不是。而在 MySQL 5.5 版本之后,带不带 _r 后缀都是 thread-safe (re-entrant) 的库了,所以理论上讲,已经不需要带 _r 的库了。
22.8.2. Simultaneous MySQL Server and MySQL Connector/C Installations
这个主要讲同时安装 MySQL server 和 MySQL Connector/C 的问题,和我要搞的事情无关
22.8.3. Example C API Client Programs
这个本应该给出如何使用 C API 来编写客户端程序的,但是其只是告诉你可以参考 client 文件夹下的源码。大概扫了一下,可以参考的,且代码量较小的是 mysqlshow.c 。
22.8.4. Building and Running C API Client Programs
这个主要讲如何构建和运行 C API 的客户端程序了,主要分为3部分说明:
22.8.4.1. Building C API Client Programs
示例说明如何编译客户端程序
shell> gcc -c `mysql_config --cflags` progname.c
shell> gcc -o progname progname.o `mysql_config --libs`
22.8.4.2. Writing C API Threaded Client Programs
讨论如何在调用 C API 的时候保证线程安全
22.8.4.3. Running C API Client Programs
避免由于系统升级导致的头文件 mysql.h 和库 libmysqlclient.a 的不匹配问题,出现问题则需要使用新的头文件和库重新编译。若依赖动态库,当出现主版本好变更的时候(如 libmysqlclient.so.17 到 libmysqlclient.so.18),则需要重新编译。
22.8.5. C API Data Structures
这里开始介绍各种数据结构(略)
================================
好吧,反正哪一个对我来说都是陌生的,那么就研究其中的 mysqlshow 试试看。 首先要干的事情就是,自己要能成功编译 mysqlshow 。
(...省略中间过程中的唧唧歪歪...)
自建工程目录如下
上述问题需要综合整体设计来给结论(读者自己先思考下)。
- 利用公司已有的 dbi 的库实现 MySQL 访问
- 基于 mysqlclient 库做开发实现 MySQL 客户端侧协议
- 自己实现 MySQL 客户端侧需要的协议
不打算用公司的 dbi 库,首先,该库基于了其他的公司库,而我并不想使用;其次,该库封装的也不是很好,之前我还查出了 4 处崩溃,不排除还有其他问题;最后,该库其实也是在 mysqlclient 上做的封装,和上面第 2条其实是一样的。所以,最终我决定选择第 2 种方式,自己搞个“山头”出来。
PS:其实开始的时候也想过采用上面的第 3 种方式,自己从底层开始实现如何支持 MySQL 客户端协议,结果“呵呵”了,难度和工作量不是一般的大~~
确定基于什么来做开发后,该做下一步目标选择了:
- 直接使用 mysqlclient 提供的 API 实现常规阻塞式调用能满足我的要求么?
- 是否需要基于 libevent 实现事件驱动式的调用模式?难度大么?
- 是否有合适的开源 MySQL 客户端实现来启发我的思路?供我参考?
可以参考的客户端实现(似乎)有:
4.5. MySQL Client Programs
4.5.1. mysql — The MySQL Command-Line Tool
4.5.2. mysqladmin — Client for Administering a MySQL Server
4.5.3. mysqlcheck — A Table Maintenance Program
4.5.4. mysqldump — A Database Backup Program
4.5.5. mysqlimport — A Data Import Program
4.5.6. mysqlshow — Display Database, Table, and Column Information
4.5.7. mysqlslap — Load Emulation Client
其中 mysql、mysqladmin、mysqlshow 和 mysqlslap 看起来很值得研究。 于是开始研究如何在 Linux下用 C 语言 API 连接 MySQL 数据库。
在 MySQL 官网上找到了如下内容,对基于 MySQL C API 实现客户端应用程序的说明(个人总结)
================================
22.8.1. MySQL C API Implementations
MySQL C API 为客户端应用程序提供了用于和 MySQL server 通信使用的基于 C 的 API。
提供了两种版本的库供使用:libmysqlclient(客户端版本)和 libmysqld(嵌入式服务器版本)。
在 Unix (以及 Unix-like)系统上,静态库为 libmysqlclient.a,动态库为 libmysqlclient.so 。
带 _r 后缀的库的含义:在 MySQL 5.5 以前,带 _r 后缀的库为 thread-safe (re-entrant) 的库,否则,则不是。而在 MySQL 5.5 版本之后,带不带 _r 后缀都是 thread-safe (re-entrant) 的库了,所以理论上讲,已经不需要带 _r 的库了。
22.8.2. Simultaneous MySQL Server and MySQL Connector/C Installations
这个主要讲同时安装 MySQL server 和 MySQL Connector/C 的问题,和我要搞的事情无关
22.8.3. Example C API Client Programs
这个本应该给出如何使用 C API 来编写客户端程序的,但是其只是告诉你可以参考 client 文件夹下的源码。大概扫了一下,可以参考的,且代码量较小的是 mysqlshow.c 。
22.8.4. Building and Running C API Client Programs
这个主要讲如何构建和运行 C API 的客户端程序了,主要分为3部分说明:
22.8.4.1. Building C API Client Programs
示例说明如何编译客户端程序
shell> gcc -c `mysql_config --cflags` progname.c
shell> gcc -o progname progname.o `mysql_config --libs`
22.8.4.2. Writing C API Threaded Client Programs
讨论如何在调用 C API 的时候保证线程安全
22.8.4.3. Running C API Client Programs
避免由于系统升级导致的头文件 mysql.h 和库 libmysqlclient.a 的不匹配问题,出现问题则需要使用新的头文件和库重新编译。若依赖动态库,当出现主版本好变更的时候(如 libmysqlclient.so.17 到 libmysqlclient.so.18),则需要重新编译。
22.8.5. C API Data Structures
这里开始介绍各种数据结构(略)
================================
好吧,反正哪一个对我来说都是陌生的,那么就研究其中的 mysqlshow 试试看。 首先要干的事情就是,自己要能成功编译 mysqlshow 。
(...省略中间过程中的唧唧歪歪...)
自建工程目录如下
1
2
3
4
5
6
7
|
[root@Betty mysql_client_test]
# ll
总计 116
-rw-r--r-- 1 root root 4130 10-25 14:33 client_priv.h
-rw-r--r-- 1 root root 2124 10-25 15:01 my_default.h
-rw-r--r-- 1 7161 wheel 25393 10-25 15:03 mysqlshow.c
-rw-r--r-- 1 root root 1686 10-25 15:01 welcome_copyright_notice.h
[root@Betty mysql_client_test]
#
|
成功编译
1
2
3
4
5
6
7
8
9
|
[root@Betty mysql_client_test]
# gcc mysqlshow.c -o mysqlshow `mysql_config --cflags` `mysql_config --libs` -DDBUG_OFF
[root@Betty mysql_client_test]
# ll
总计 116
-rw-r--r-- 1 root root 4130 10-25 14:33 client_priv.h
-rw-r--r-- 1 root root 2124 10-25 15:01 my_default.h
-rwxr-xr-x 1 root root 66953 10-25 16:23 mysqlshow
-rw-r--r-- 1 7161 wheel 25393 10-25 15:03 mysqlshow.c
-rw-r--r-- 1 root root 1686 10-25 15:01 welcome_copyright_notice.h
[root@Betty mysql_client_test]
#
|
执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
[root@Betty mysql_client_test]
# ./mysqlshow --help
.
/mysqlshow
Ver 9.10 Distrib 5.6.10,
for
Linux (x86_64)
Copyright (c) 2000, 2013, Oracle and
/or
its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and
/or
its
affiliates. Other names may be trademarks of their respective
owners.
Shows the structure of a MySQL database (databases, tables, and columns).
Usage: .
/mysqlshow
[OPTIONS] [database [table [column]]]
If last argument contains a shell or SQL wildcard (*,?,% or _)
then
only
what's matched by the wildcard is shown.
If no database is given
then
all matching databases are shown.
If no table is given,
then
all matching tables
in
database are shown.
If no column is given,
then
all matching columns and column types
in
table
are shown.
Default options are
read
from the following files
in
the given order:
/etc/my
.cnf
/etc/mysql/my
.cnf
/usr/local/mysql/etc/my
.cnf ~/.my.cnf
The following
groups
are
read
: mysqlshow client
The following options may be given as the first argument:
--print-defaults Print the program argument list and
exit
.
--no-defaults Don't
read
default options from any option
file
,
except
for
login
file
.
--defaults-
file
=
# Only read default options from the given file #.
--defaults-extra-
file
=
# Read this file after the global files are read.
--defaults-group-suffix=
#
Also
read
groups
with concat(group, suffix)
--login-path=
# Read this path from the login file.
--bind-address=name IP address to bind to.
-c, --character-sets-
dir
=name
Directory
for
character
set
files.
--default-character-
set
=name
Set the default character
set
.
--count Show number of rows per table (may be slow
for
non-MyISAM
tables).
-C, --compress Use compression
in
server
/client
protocol.
-
#, --debug[=name] Output debug log. Often this is 'd:t:o,filename'.
--debug-check Check memory and
open
file
usage at
exit
.
--debug-info Print some debug info at
exit
.
--default-auth=name Default authentication client-side plugin to use.
-?, --help Display this help and
exit
.
-h, --host=name Connect to host.
-i, --status Shows a lot of extra information about each table.
-k, --keys Show keys
for
table.
-p, --password[=name]
Password to use when connecting to server. If password is
not given, it's solicited on the
tty
.
--plugin-
dir
=name Directory
for
client-side plugins.
-P, --port=
# Port number to use for connection or 0 for default to, in
order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/services
, built-
in
default (3306).
--protocol=name The protocol to use
for
connection (tcp, socket, pipe,
memory).
-t, --show-table-
type
Show table
type
column.
-S, --socket=name The socket
file
to use
for
connection.
-u, --user=name User
for
login
if
not current user.
-
v
, --verbose More verbose output; you can use this multiple
times
to
get even
more
verbose output.
-V, --version Output version information and
exit
.
Variables (--variable-name=value)
and boolean options {FALSE|TRUE} Value (after reading options)
--------------------------------- ----------------------------------------
bind-address (No default value)
character-sets-
dir
(No default value)
default-character-
set
auto
count FALSE
compress FALSE
debug-check FALSE
debug-info FALSE
default-auth (No default value)
host (No default value)
status FALSE
keys FALSE
plugin-
dir
(No default value)
port 0
show-table-
type
FALSE
socket (No default value)
user (No default value)
[root@Betty mysql_client_test]
#
|
确实和源码编译 MySQL 得到的 mysqlshow 一致,到此暂时走出了研究 MySQL 客户端实现的第一步。可以稍微总结一下了:
- 直接使用 MySQL C API 来编写程序是阻塞的还是非阻塞的?
- MySQL C API 能够和 libevent 结合在一起么? 或者说哪些 API 可以?
- 是否需要基于 libevent 的 MySQL 协议实现?
上述问题需要综合整体设计来给结论(读者自己先思考下)。