1. 简介
除了通过DBD::mysql来访问MySQL服务器之外,我们还可以通过MySQL C API来直接访问MySQL服务器,这需要使用mysqlclient库,MySQL的大多数客户端API(除了Java和.NET)都是通过这个库来和MySQL服务器通讯的,而这个库正是用C编写的。
下面简单介绍如何通过MySQL C API来访问MySQL服务器,函数的详细说明请参考《MySQL参考手册》。
2. 代码编写和编译
在源代码中需要加入
#include <mysql.h>
在编译时需要加入以下参数(假设MySQL安装位置为/usr/local/mysql, 非RPM方式安装)
-I/usr/local/mysql/include -L/usr/local/mysql/lib -lmysqlclient
3. 连接MySQL服务器
在连接MySQL服务器之前,需要初始化一个MYSQL结构,该结构在几乎所有的MySQL C API函数(除了预处理语句相关的函数)中都会用到。
MYSQL *mysql_init(MYSQL *mysql)
然后就可以连接MySQL服务器了。
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd,
const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)
这里推荐采用另一种方式来进行连接。先用MYSQL_READ_DEFAULT_FILE作为选项名来调用mysql_options(), 再调用mysql_real_connect()来连接服务器
mysql_options(*mysql, MYSQL_READ_DEFAULT_FILE, "my.cnf")
mysql_real_connect(*mysql, NULL, NULL, NULL, NULL, 0, NULL, 0)
my.cnf文件中记录了连接MySQL服务器所需的各项参数(地址,端口,用户名,密码,数据库,字符集,Unix Socket等)。这样可以灵活的修改连接参数而不必重新编译程序。
如果要关闭连接,则调用mysql_close()
void mysql_close(MYSQL *mysql)
4. 执行查询
调用mysql_query()来执行SQL语句,如果语句中包含二进制数据,则需要调用mysql_real_query().
int mysql_query(MYSQL *mysql, const char *stmt_str)
int mysql_real_query(MYSQL *mysql, const char *stmt_str, unsigned long length)
若执行的是UPDATE, DELETE或INSERT语句,则可通过mysql_affected_rows()获知受影响的记录数。
my_ulonglong mysql_affected_rows(MYSQL *mysql)
还可以通过mysql_insert_id()来获取由最近的UPDATE或INSERT语句生成的自增值。
my_ulonglong mysql_insert_id(MYSQL *mysql)
若执行的是SELECT语句,则有两种方式来获取结果集。
一种方式是通过mysql_store_result()将整个结果集全部取回来。
MYSQL_RES *mysql_store_result(MYSQL *mysql)
另一种方式则是调用mysql_use_result()初始化获取操作,但暂时不取回任何记录。
MYSQL_RES *mysql_use_result(MYSQL *mysql)
然后通过mysql_fetch_row()来访问每一条记录。
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
若先前调用的是mysql_store_result(), 则直接在本地访问记录;若先前调用的是mysql_use_result(), 则此时才到服务器上去获取记录。
当处理完结果集后,调用mysql_free_result()来释放它所占的内存。
void mysql_free_result(MYSQL_RES *result)
此外,可以调用mysql_errno()和mysql_error()来获知最近执行的API函数的错误代码和错误信息。
unsigned int mysql_errno(MYSQL *mysql)
const char *mysql_error(MYSQL *mysql)
5. 预处理语句(Prepared Statements)
MySQL C API还提供了另一种方式来执行SQL语句,即先预处理(prepare)再执行(execute). 对于多次执行的SQL语句,该方式可以提高其执行效率。具体步骤如下:
1. 调用mysql_stmt_init()创建语句句柄,该句柄在随后的函数调用中都要用到。
MYSQL_STMT *mysql_stmt_init(MYSQL *mysql)
2. 调用mysql_stmt_prepare()对SQL语句进行预处理
int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *stmt_str, unsigned long length)
3. 如果SQL语句中有参数,则需要调用mysql_stmt_bind_param()进行参数绑定。
my_bool mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
如果参数的类型为TEXT或BLOB, 并且数据量很大,可以调用mysql_stmt_send_long_data()来向服务器发送数据。
my_bool mysql_stmt_send_long_data(MYSQL_STMT *stmt, unsigned int parameter_number, const char *data, unsigned long length)
4. 调用mysql_stmt_execute()来执行查询。
int mysql_stmt_execute(MYSQL_STMT *stmt)
5. 若查询不产生结果集,可以调用mysql_stmt_affected_rows()和my_ulonglong mysql_stmt_insert_id(MYSQL_STMT *stmt)来获得被改变的记录数和生成的自增值。
my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT *stmt)
my_ulonglong mysql_stmt_insert_id(MYSQL_STMT *stmt)
否则,执行mysql_stmt_bind_result()对结果集中的字段进行绑定。
my_bool mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
6. 调用mysql_stmt_fetch()来逐行获取结果集中的记录。
int mysql_stmt_fetch(MYSQL_STMT *stmt)
在调用mysql_stmt_fetch()之前,还可以执行mysql_stmt_store_result()将结果集预先缓存到本地。
int mysql_stmt_store_result(MYSQL_STMT *stmt)
7. 重复步骤3-6, 每次使用不同的实参来执行查询。
8. 调用mysql_stmt_close()关闭句柄,释放资源
my_bool mysql_stmt_close(MYSQL_STMT *)
此外,可以调用mysql_stmt_errno()和mysql_stmt_error()来获知最近执行的预处理语句API函数的错误代码和错误信息。
unsigned int mysql_stmt_errno(MYSQL_STMT *stmt)
const char *mysql_stmt_error(MYSQL_STMT *stmt)
6. 参考
"MySQL Reference Manual" Chapter 27 Section 2