官网:https://dev.mysql.com/doc/refman/8.0/en/c-api.html
1 API介绍
1.1 初始化函数
MYSQL *mysql_init(MYSQL *mysql)
mysql 可以传 NULL
返回值:分配的句柄 MYSQL*指针
1.2 设置连接选项
int mysql_options(MYSQL *mysql, enum mysql_option option, const char *arg)
描述
可用于设置额外的连接选项,并影响连接的行为。可多次调用该函数来设置数个选项。
应在mysql_init()之后、以及mysql_connect()或mysql_real_connect()之前调用mysql_options()。
选项参量指的是你打算设置的选项。Arg参量是选项的值。如果选项是整数,那么arg应指向整数的值。
范例
my_bool reconnect = true;
mysql_options(m_mysql, MYSQL_OPT_RECONNECT, &reconnect);
mysql_options(m_mysql, MYSQL_SET_CHARSET_NAME, "utf8mb4");
MySQL在5.5.3之后增加了这个utf8mb4的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode。好在utf8mb4是utf8的超集,除了将编码改为utf8mb4外不需要做其他转换。
要在 Mysql 中保存 4 字节长度的 UTF-8 字符,需要使用 utf8mb4 字符集,但只有 5.5.3 版本以后的才支持(查看版本: select version();)。我觉得,为了获取更好的兼容性,应该总是使用 utf8mb4 而非 utf8. 对于 CHAR 类型数据,utf8mb4 会多消耗一些空间,根据 Mysql 官方建议,使用 VARCHAR 替代 CHAR。
1.3 连接到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 初始化的句柄指针
- host 主机地址
- user 用户名 – mysql数据库 root
- passwd 用户的密码
- db 要连接的数据库
- port 端口 一般填0,mysql默认端口 3306
- unix_socket 本地套接字 ,一般填NULL
- client_flag 连接标志 一般填0
返回值:成功返回 连接句柄,失败返回 NULL
1.4 设定登陆的字符集 – 登陆之后
int mysql_set_character_set(MYSQL *mysql, char *csname)
参数:
- mysql 连接句柄
- csname 字符集的名称 utf8
1.5 query功能非常强大 增删改查都可以
int mysql_query(MYSQL *mysql, const char *query)
参数介绍:
- mysql 连接句柄
- query 执行的sql
反回值:
- 成功 返回 0
- 失败 返回 非0
1.6 获得结果集的函数
MYSQL_RES *mysql_store_result(MYSQL *mysql)
返回值:
如果读取结果集失败,mysql_store_result()还会返回Null指针。
通过检查mysql_error()是否返回非空字符串,mysql_errno()是否返回非0值,或mysql_field_count()是否返回0,可以检查是否出现了错误。
范例
MYSQL_RES* res = mysql_store_result(m_mysql);
if (!res) {
log_error("mysql_store_result failed: %s", mysql_error(m_mysql));
return NULL;
}
1.7 释放结果集
void mysql_free_result(MYSQL_RES *result)
范例:
if (m_res) {
mysql_free_result(m_res);
m_res = NULL;
}
1.8 获取查询的显示列的长度
unsigned int mysql_num_fields(MYSQL_RES *result)
描述:返回结果集中的行数。
注意,你可以从指向结果集的指针或指向连接句柄的指针获得行数。如果mysql_store_result()或mysql_use_result()返回NULL,应使用连接句柄(因而没有结果集指针)。在该情况下,可调用mysql_field_count()来判断mysql_store_result()是否生成了非空结果。这样,客户端程序就能采取恰当的行动,而不需要知道查询是否是SELECT语句(或类似SELECT的语句)。在下面的示例中,介绍了执行该操作的方式。
范例
int num_fields = mysql_num_fields(m_res);
MYSQL_FIELD* fields = mysql_fetch_fields(m_res);
1.9 获取列信息
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)
描述
返回采用MYSQL_FIELD结构的结果集的列。重复调用该函数,以检索关于结果集中所有列的信息。未剩余字段时,mysql_fetch_field()返回NULL。
每次执行新的SELECT查询时,将复位mysql_fetch_field(),以返回关于第1个字段的信息。调用mysql_field_seek()也会影响mysql_fetch_field()返回的字段。
如果调用了mysql_query()以在表上执行SELECT,但未调用mysql_store_result(),如果调用了mysql_fetch_field()以请求BLOB字段的长度,MySQL将返回默认的Blob长度(8KB)。之所以选择8KB是因为MySQL不知道BLOB的最大长度。应在日后使其成为可配置的。一旦检索了结果集,field->max_length将包含特定查询中该列的最大值的长度。
返回值
当前列的MYSQL_FIELD结构。如果未剩余任何列,返回NULL。
1.10 取出一行信息
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
描述
检索结果集的下一行。在mysql_store_result()之后使用时,如果没有要检索的行,mysql_fetch_row()返回NULL。在mysql_use_result()之后使用时,如果没有要检索的行或出现了错误,mysql_fetch_row()返回NULL。
行内值的数目由mysql_num_fields(result)给出。如果行中保存了调用mysql_fetch_row()返回的值,将按照row[0]到row[mysql_num_fields(result)-1],访问这些值的指针。行中的NULL值由NULL指针指明。
可以通过调用mysql_fetch_lengths()来获得行中字段值的长度。对于空字段以及包含NULL的字段,长度为0。通过检查字段值的指针,能够区分它们。如果指针为NULL,字段为NULL,否则字段为空。
返回值
下一行的MYSQL_ROW结构。如果没有更多要检索的行或出现了错误,返回NULL。
1.11 显示受影响的行数
my_ulonglong mysql_affected_rows(MYSQL *mysql)
描述
返回上次UPDATE更改的行数,上次DELETE删除的行数,或上次INSERT语句插入的行数。对于UPDATE、DELETE或INSERT语句,可在mysql_query()后立刻调用。对于SELECT语句,mysql_affected_rows()的工作方式与mysql_num_rows()类似。
返回值
大于0的整数表明受影响或检索的行数。“0”表示UPDATE语句未更新记录,在查询中没有与WHERE匹配的行,或未执行查询。“-1”表示查询返回错误,或者,对于SELECT查询,在调用mysql_store_result()之前调用了mysql_affected_rows()。由于mysql_affected_rows()返回无符号值,通过比较返回值和“(my_ulonglong)-1”或等效的“(my_ulonglong)~0”,检查是否为“-1”。
/* gcc -o connect mysql.c -lmysqlclient -I/usr/include/mysql -L/usr/lib64/mysql/ */
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>
#include <unistd.h>
#define _USER_ "root" /* 用户名 */
#define _HOST_ "127.0.0.1" /* host */
#define _PASSWD_ "123456" /* root 用户名密码 */
#define _DB_ "teamtalk" /* 库名 */
#define _PORT_ 3306 /* port */
/* 打印信息 结果集 */
void show_information( MYSQL_RES * res, MYSQL *mysql )
{
int i;
MYSQL_ROW row; /* */
/* unsigned long *lengths; */
unsigned int num_fields;
MYSQL_FIELD *field; /* 字段名 */
/* 数据的长度unsigned int mysql_num_fields(MYSQL_RES *result) */
num_fields = mysql_num_fields( res );
/*
* 返回列长unsigned long *mysql_fetch_lengths(MYSQL_RES *result)
* lengths = mysql_fetch_lengths(res);
*/
printf( "num_fields = [%d]\n", num_fields );
/* 字段名 */
for ( i = 0; i < num_fields, field = mysql_fetch_field( res ); i++ )
{
printf( " %s\t", field->name );
}
printf( "\n" );
printf( "--------------------------------------------------------------\n" );
while ( (row = mysql_fetch_row( res ) ) )
{
for ( i = 0; i < num_fields; i++ )
{
printf( "%s \t", row[i] ? row[i] : NULL );
}
printf( "\n" );
}
/* 释放结果集 */
mysql_free_result( res );
printf( "--------------------------------------------------------------\n" );
/* 显示受影响的行数 */
printf( " %ld rows in set\n", (long) mysql_affected_rows( mysql ) );
}
int main( int argc, char *argv[] )
{
int ret, i;
MYSQL *mysql;
MYSQL_RES * res;
char strsql[512] = { 0 };
/* 1,mysql_init 初始化 */
mysql = mysql_init( NULL );
if ( mysql == NULL )
{
printf( "mysql_init error\n" );
return(-1);
}
/* 2,mysql_real_connect链接 */
mysql = mysql_real_connect( mysql,
_HOST_,
_USER_,
_PASSWD_,
_DB_,
0,
NULL,
0 );
if ( mysql == NULL )
{
printf( "mysql_real_connect error\n" );
return(-1);
}
printf( "connect mysql ok\n" );
/* 处理字符问题的函数 */
if ( mysql_set_character_set( mysql, "utf8" ) != 0 )
{
printf( " mysql_set_character_set error\n" );
mysql_close( mysql );
exit( 1 );
}
/* ===========================输入sql语句====================== */
while ( 1 )
{
memset( strsql, 0x00, sizeof(strsql) );
write( STDOUT_FILENO, "yoursql>", 8 );
// select * from IMUser;
/* 读取client输入的sql字符串 */
read( STDIN_FILENO, strsql, sizeof(strsql) );
/* 退出的处理 */
if ( strncasecmp( strsql, "quit", 4 ) == 0 )
{
printf( "client 退出处理\n" );
break;
}
/* 输入sql的 */
ret = mysql_query( mysql, strsql );
if ( ret )
{
printf( "mysql_query error\n" );
continue;
}
res = mysql_store_result( mysql );
/*有结果集的处理 */
if ( res != NULL )
{
show_information( res, mysql );
}else {
/* 显示受影响的行数 */
printf( " Query OK, %ld row affected\n", (long) mysql_affected_rows( mysql ) );
}
}
/* 关闭mysql */
mysql_close( mysql );
return(0);
}
2 SQL预处理 防止注入和增加效率
流程图
2.1 预处理初始化
MYSQL_STMT *mysql_stmt_init(MYSQL *mysql)
描述
创建MYSQL_STMT句柄。对于该句柄,应使用mysql_stmt_close(MYSQL_STMT *)释放。
返回值
成功时,返回指向MYSQL_STMT结构的指针。如果内存溢出,返回NULL。
2.2 插入预处理语句
int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length)
描述
给定mysql_stmt_init()返回的语句句柄,准备字符串查询指向的SQL语句,并返回状态值。字符串长度应由“length”参量给出。字符串必须包含1条SQL语句。不应为语句添加终结用分号(‘;’)或\g。
通过将问号字符“?”嵌入到SQL字符串的恰当位置,应用程序可包含SQL语句中的一个或多个参数标记符。
标记符仅在SQL语句中的特定位置时才是合法的。例如,它可以在INSERT语句的VALUES()列表中(为行指定列值),或与WHERE子句中某列的比较部分(用以指定比较值)。但是,对于ID(例如表名或列名),不允许使用它们,不允许指定二进制操作符(如等于号“=”)的操作数。后一个限制是有必要的,原因在于,无法确定参数类型。一般而言,参数仅在DML(数据操作语言)语句中才是合法的,在DDL(数据定义语言)语句中不合法。
执行语句之前,必须使用mysql_stmt_bind_param(),将参数标记符与应用程序变量绑定在一起。
返回值
如果成功处理了语句,返回0。如果出现错误,返回非0值。
2.3 获取参数
unsigned long mysql_stmt_param_count(MYSQL_STMT *stmt)
描述
返回预处理语句中参数标记符的数目。
返回值
表示语句中参数数目的无符号长整数。
2.4 参数的绑定
my_bool mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
描述
mysql_stmt_bind_param()用于为SQL语句中的参数标记符绑定数据,以传递给mysql_stmt_prepare()。它使用MYSQL_BIND结构来提供数据。“bind”是MYSQL_BIND结构的某一数组的地址。按照客户端库的预期,对于查询中出现的每个“?”参数标记符,数组中均包含1个元素。
假定你准备了下述语句:
INSERT INTO mytbl VALUES(?,?,?)
绑定参数时,MYSQL_BIND结构的数组包含3个元素,并能声明如下:
MYSQL_BIND bind[3];
2.5 预处理执行
int mysql_stmt_execute(MYSQL_STMT *stmt)
描述
mysql_stmt_execute()执行与语句句柄相关的预处理查询。在该调用期间,将当前绑定的参数标记符的值发送到服务器,服务器用新提供的数据替换标记符。
如果语句是UPDATE、DELETE或INSERT,通过调用mysql_stmt_affected_rows(),可发现更改、删除或插入的总行数。如果这是诸如SELECT等能生成结果集的语句,调用任何其他能导致查询处理的函数之前,必须调用mysql_stmt_fetch()来获取数据。关于如何获取结果的更多信息,请参见25.2.7.11节,“mysql_stmt_fetch()”。
对于生成结果集的语句,执行语句之前,可通过调用mysql_stmt_attr_set(),请求mysql_stmt_execute()为语句打开光标。如果多次执行某一语句,在打开新的光标前,mysql_stmt_execute()将关闭任何已打开的光标。
返回值
如果执行成功,返回0。如果出现错误,返回非0值。
1.6 返回预处理的行数
my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT *stmt)
描述
返回上次执行语句更改、删除或插入的总行数。对于UPDATE、DELETE或INSERT语句,可在mysql_stmt_execute()之后立刻调用它们。对于SELECT语句,mysql_stmt_affected_rows()的工作方式类似于mysql_num_rows()。
返回值
大于0的整数指明了受影响或检索的行数。对于UPDATE语句,“0”表明未更新任何记录,在查询中没有与WHERE子句匹配的行,或尚未执行任何查询。“-1”表明返回了错误,或对SELECT查询,在调用mysql_stmt_store_result()之前调用了mysql_stmt_affected_rows()。由于mysql_stmt_affected_rows()返回无符号值,可通过比较返回值和“(my_ulonglong)-1”(或等效的“(my_ulonglong)~0”),检查“-1”。
/* gcc -o insert mysql_insert.c -lmysqlclient -I/usr/include/mysql -L/usr/lib64/mysql/ */
/* 预处理方式api处理 -- insert */
#include <stdio.h>
#include "mysql.h"
#include <stdlib.h>
#include <string.h>
#define _HOST_ "localhost" /* 主机 */
#define _USER_ "root" /* mysql用户,非主机 */
#define _PASSWD_ "123456" /* 密码 */
#define _DBNAME_ "teamtalk" /* 库名 */
#define STRING_SIZE 50
#define DROP_SAMPLE_TABLE "DROP TABLE IF EXISTS test_table" /* if EXISTS 好处 是如果表不存在,执行不会报错 */
#define CREATE_SAMPLE_TABLE "CREATE TABLE test_table(col1 INT,\
col2 VARCHAR(40),\
col3 SMALLINT,\
col4 TIMESTAMP)"
#define INSERT_SAMPLE "INSERT INTO test_table(col1,col2,col3) VALUES(?,?,?)"
void prepare_insert( MYSQL *mysql );
int main()
{
/* 1.初始化 */
MYSQL * mysql = NULL;
mysql = mysql_init( NULL );
if ( mysql == NULL )
{
printf( "mysql init err\n" );
exit( 1 );
}
/* 2.连接 */
mysql = mysql_real_connect( mysql, _HOST_, _USER_, _PASSWD_, _DBNAME_, 0, NULL, 0 );
if ( mysql == NULL )
{
printf( "mysql_real_connect connect err\n" );
exit( 1 );
}
printf( "welcome to mysql \n" );
prepare_insert( mysql );
/* 3.关闭 */
mysql_close( mysql );
return(0);
}
void prepare_insert( MYSQL *mysql )
{
MYSQL_STMT *stmt; /* 预处理的句柄 -- 标识进程内唯一的一个预处理的sql */
MYSQL_BIND bind[3]; /* 绑定变量 */
my_ulonglong affected_rows;
int param_count;
short small_data;
int int_data;
char str_data[STRING_SIZE];
unsigned long str_length;
my_bool is_null;
if ( mysql_query( mysql, DROP_SAMPLE_TABLE ) ) /*删除表 */
{
fprintf( stderr, " DROP TABLE failed\n" );
fprintf( stderr, " %s\n", mysql_error( mysql ) );
exit( 0 );
}
if ( mysql_query( mysql, CREATE_SAMPLE_TABLE ) ) /* 创建表 */
{
fprintf( stderr, " CREATE TABLE failed\n" );
fprintf( stderr, " %s\n", mysql_error( mysql ) );
exit( 0 );
}
/* Prepare an INSERT query with 3 parameters */
/* (the TIMESTAMP column is not named; the server */
/* sets it to the current date and time) */
stmt = mysql_stmt_init( mysql ); /* 预处理的初始化 */
if ( !stmt )
{
fprintf( stderr, " mysql_stmt_init(), out of memory\n" );
exit( 0 );
}
if ( mysql_stmt_prepare( stmt, INSERT_SAMPLE, strlen( INSERT_SAMPLE ) ) ) /* insert 语句 的预处理 */
{
fprintf( stderr, " mysql_stmt_prepare(), INSERT failed\n" );
fprintf( stderr, " %s\n", mysql_stmt_error( stmt ) );
exit( 0 );
}
fprintf( stdout, " prepare, INSERT successful\n" );
/* Get the parameter count from the statement */
param_count = mysql_stmt_param_count( stmt ); /* 获得参数个数 */
fprintf( stdout, " total parameters in INSERT: %d\n", param_count );
if ( param_count != 3 ) /* validate parameter count */
{
fprintf( stderr, " invalid parameter count returned by MySQL\n" );
exit( 0 );
}
/* Bind the data for all 3 parameters */
memset( bind, 0, sizeof(bind) );
/* INTEGER PARAM */
/* This is a number type, so there is no need to specify buffer_length */
bind[0].buffer_type = MYSQL_TYPE_LONG; /* 对应int类型 */
bind[0].buffer = (char *) &int_data; /* 内存地址的映射 */
bind[0].is_null = 0;
bind[0].length = 0;
/* STRING PARAM */
bind[1].buffer_type = MYSQL_TYPE_STRING;
bind[1].buffer = (char *) str_data; /* char 100 */
bind[1].buffer_length = STRING_SIZE;
bind[1].is_null = 0;
bind[1].length = &str_length;
/* SMALLINT PARAM */
bind[2].buffer_type = MYSQL_TYPE_SHORT;
bind[2].buffer = (char *) &small_data;
bind[2].is_null = &is_null; /* 是否为null的指示器 */
bind[2].length = 0;
/* Bind the buffers */
if ( mysql_stmt_bind_param( stmt, bind ) ) /* 绑定变量 参数绑定 */
{
fprintf( stderr, " mysql_stmt_bind_param() failed\n" );
fprintf( stderr, " %s\n", mysql_stmt_error( stmt ) );
exit( 0 );
}
/* 第一波赋值 */
int_data = 10; /* integer */
strncpy( str_data, "MySQL", STRING_SIZE ); /* string */
str_length = strlen( str_data );
/* INSERT INTO test_table(col1,col2,col3) VALUES(10,'MySQL',null) */
/* INSERT SMALLINT data as NULL */
is_null = 1; /* 指示插入的第三个字段是否为null */
/* insert into test_table(col1,col2,col3) values(10,'MySQL',null); */
/* Execute the INSERT statement - 1*/
if ( mysql_stmt_execute( stmt ) ) /* 预处理的执行,第一次执行 */
{
fprintf( stderr, " mysql_stmt_execute(), 1 failed\n" );
fprintf( stderr, " %s\n", mysql_stmt_error( stmt ) );
exit( 0 );
}
/* Get the total number of affected rows */
affected_rows = mysql_stmt_affected_rows( stmt ); /* 预处理的影响条数 */
fprintf( stdout, " total affected rows(insert 1): %lu\n",
(unsigned long) affected_rows );
if ( affected_rows != 1 ) /* validate affected rows */
{
fprintf( stderr, " invalid affected rows by MySQL\n" );
exit( 0 );
}
/* 第二波赋值 */
int_data = 1000;
strncpy( str_data, "The most popular Open Source database", STRING_SIZE );
str_length = strlen( str_data );
small_data = 1000; /* smallint */
is_null = 1; /* reset */
/* INSERT INTO test_table(col1,col2,col3) VALUES(1000,'The most popular Open Source database',1000) */
/* insert into test_table(col1,col2,col3) values(1000,'The most popular Open Source database',1000); */
/* Execute the INSERT statement - 2*/
if ( mysql_stmt_execute( stmt ) ) /* 第二次执行 */
{
fprintf( stderr, " mysql_stmt_execute, 2 failed\n" );
fprintf( stderr, " %s\n", mysql_stmt_error( stmt ) );
exit( 0 );
}
/* Get the total rows affected */
affected_rows = mysql_stmt_affected_rows( stmt );
fprintf( stdout, " total affected rows(insert 2): %lu\n",
(unsigned long) affected_rows );
if ( affected_rows != 1 ) /* validate affected rows */
{
fprintf( stderr, " invalid affected rows by MySQL\n" );
exit( 0 );
}
/* Close the statement */
if ( mysql_stmt_close( stmt ) )
{
fprintf( stderr, " failed while closing the statement\n" );
fprintf( stderr, " %s\n", mysql_stmt_error( stmt ) );
exit( 0 );
}
}
3 查询预处理
流程图
api介绍
MYSQL_RES *mysql_stmt_param_metadata(MYSQL_STMT *stmt)
提前指定结果集的操作
/* gcc -o select mysql_select.c -lmysqlclient -I/usr/include/mysql -L/usr/lib64/mysql/ */
/* SELECT id, name, sex FROM IMUser; 查询语句的使用 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql.h>
#define _USER_ "root" /* 用户名 */
#define _HOST_ "127.0.0.1" /* host */
#define _PASSWD_ "123456" /* root 用户名密码 */
#define _DB_ "teamtalk" /* 库名 */
#define _PORT_ 3306 /* port */
/* ============================stmt ====================================== */
#define STRING_SIZE 50
/* mysql 查询语句 */
#define SELECT_SAMPLE "SELECT id, name, sex FROM IMUser"
void seach_information( MYSQL *mysql )
{
int i, count = 0;;
MYSQL_STMT *stmt; /* */
MYSQL_BIND bind[3]; /* 条件变量 */
MYSQL_RES *prepare_meta_result; /* 结果集 */
unsigned long length[3];
int param_count, column_count, row_count;
int int_data; /* 序号 */
char str_name[STRING_SIZE]; /* 姓名 */
char str_loc[STRING_SIZE];
my_bool is_null[3]; /* 参数的控制 */
my_ulonglong row_unm;
/*
* ===========================init start=========================
* 初始化sql预处理语句
*/
stmt = mysql_stmt_init( mysql );
if ( !stmt )
{
fprintf( stderr, " mysql_stmt_init(), out of memory\n" );
exit( 0 );
}
/*
* 绑定参数my_bool mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
* mysql_stmt_bind_param(stmt, bind);
*/
if ( mysql_stmt_prepare( stmt, SELECT_SAMPLE, strlen( SELECT_SAMPLE ) ) )
{
fprintf( stderr, " mysql_stmt_prepare(), SELECT failed\n" );
fprintf( stderr, " %s\n", mysql_stmt_error( stmt ) );
exit( 0 );
}
fprintf( stdout, " prepare, SELECT successful\n" );
fprintf( stdout, " total parameters in SELECT: %d\n", param_count );
param_count = mysql_stmt_param_count( stmt );
if ( param_count != 0 ) /* validate parameter count */
{
fprintf( stderr, " invalid parameter count returned by MySQL\n" );
exit( 0 );
}
prepare_meta_result = mysql_stmt_result_metadata( stmt );
if ( !prepare_meta_result )
{
fprintf( stderr,
" mysql_stmt_result_metadata(), returned no meta information\n" );
fprintf( stderr, " %s\n", mysql_stmt_error( stmt ) );
exit( 0 );
}
column_count = mysql_num_fields( prepare_meta_result );
fprintf( stdout, " total columns in SELECT statement: %d\n", column_count );
if ( column_count != 3 ) /* validate column count */
{
fprintf( stderr, " invalid column count returned by MySQL\n" );
exit( 0 );
}
/* mysql_stmt_execute(stmt); //发送占位符到mysql数据库上???? */
if ( mysql_stmt_execute( stmt ) )
{
fprintf( stderr, " mysql_stmt_execute(), failed\n" );
fprintf( stderr, " %s\n", mysql_stmt_error( stmt ) );
exit( 0 );
}
/* 初始化参数 */
memset( bind, 0, sizeof(bind) );
/* INTEGER COLUMN */
bind[0].buffer_type = MYSQL_TYPE_LONG;
bind[0].buffer = (char *) &int_data;
bind[0].is_null = &is_null[0];
bind[0].length = &length[0];
/* varchar -- MYSQL_TYPE_VAR_STRING */
/* name COLUMN */
bind[1].buffer_type = MYSQL_TYPE_VAR_STRING;
bind[1].buffer = (char *) str_name;
bind[1].buffer_length = STRING_SIZE;
bind[1].is_null = &is_null[1];
bind[1].length = &length[1];
/* loc COLUMN */
bind[2].buffer_type = MYSQL_TYPE_VAR_STRING;
bind[2].buffer = (char *) &str_loc;
bind[2].buffer_length = STRING_SIZE;
bind[2].is_null = &is_null[2];
bind[2].length = &length[2];
/* 绑定数据 */
mysql_stmt_bind_result( stmt, bind );
mysql_stmt_store_result( stmt ); /* */
/* init row */
row_count = 0;
/* 查询的结果 */
row_unm = mysql_stmt_num_rows( stmt );
/*
* 打印数据
* mysql_stmt_fetch(stmt);
* mysql_stmt_fetch(stmt);
*/
printf( "row_unm = %ld\n", row_unm );
for ( i = 0; i < row_unm; i++ )
{
mysql_stmt_fetch( stmt );
row_count++;
fprintf( stdout, " row %d\n", row_count );
/* column 1 */
fprintf( stdout, " column1 (integer) : " );
if ( is_null[0] )
fprintf( stdout, " NULL\n" );
else
fprintf( stdout, " %d(%ld)\n", int_data, length[0] );
/* column 2 */
fprintf( stdout, " column2 (string) : " );
if ( is_null[1] )
fprintf( stdout, " NULL\n" );
else
fprintf( stdout, " %s(%ld)\n", str_name, length[1] );
/* column 3 */
fprintf( stdout, " column3 (string) : " );
if ( is_null[2] )
fprintf( stdout, " NULL\n" );
else
fprintf( stdout, " %s(%ld)\n", str_loc, length[2] );
fprintf( stdout, "\n" );
/* break; */
}
/* 释放内存 */
/* Validate rows fetched */
// if ( row_count != 10 )
// {
// fprintf( stderr, " MySQL failed to return all rows\n" );
// exit( 0 );
// }
/* Free the prepared result metadata */
mysql_free_result( prepare_meta_result );
/* Close the statement */
mysql_stmt_close( stmt );
}
/* ===================================================================== */
int main( int argc, char *argv[] )
{
int ret, i;
MYSQL *mysql;
MYSQL_RES * res;
MYSQL_ROW row; /* */
/* unsigned long *lengths; */
unsigned int num_fields;
MYSQL_FIELD *field; /* 字段名 */
/* 1,mysql_init 初始化 */
mysql = mysql_init( NULL );
if ( mysql == NULL )
{
printf( "mysql_init error\n" );
return(-1);
}
/* 2,mysql_real_connect链接 */
mysql = mysql_real_connect( mysql,
_HOST_,
_USER_,
_PASSWD_,
_DB_,
0,
NULL,
0 );
if ( mysql == NULL )
{
printf( "mysql_real_connect error\n" );
return(-1);
}
printf( "connect mysql ok\n" );
/* 设置一下字符编码utf8 */
if ( mysql_set_character_set( mysql, "utf8" ) )
{
printf( " mysql_set_character_set error\n");
return(-1);
}
seach_information( mysql );
/* 关闭mysql */
mysql_close( mysql );
return(0);
}
4 事务的介绍
/* gcc -o transaction mysql_transaction.c -lmysqlclient -I/usr/include/mysql -L/usr/lib64/mysql/ */
/* mysql中的事务 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mysql.h"
#define SET_TRAN "SET AUTOCOMMIT=0" /* 手动commit ————手动commit */
#define UNSET_TRAN "SET AUTOCOMMIT=1" /* 自动commit */
#define _HOST_ "127.0.0.1"
#define _USER_ "root"
#define _PASSWD_ "123456"
#define _DBNAME_ "teamtalk"
/* 设置事务为手动提交 */
int mysql_OperationTran( MYSQL *mysql )
{
/* --开启事务 */
int ret = mysql_query( mysql, "start transaction" ); /* 开启一次事务 start transaction */
if ( ret != 0 )
{
printf( "mysql_OperationTran query start err: %s\n", mysql_error( mysql ) );
return(ret);
}
/* --设置事务为手动提交 */
ret = mysql_query( mysql, SET_TRAN ); /* set autocommmit = 0 */
if ( ret != 0 )
{
printf( "mysql_OperationTran query set err: %s\n", mysql_error( mysql ) );
return(ret);
}
return(ret);
}
/* 设置事务为自动提交 */
int mysql_AutoTran( MYSQL *mysql )
{
/* --开启事务 */
int ret = mysql_query( mysql, "start transaction" );
if ( ret != 0 )
{
printf( "mysql_AutoTran query start err: %s\n", mysql_error( mysql ) );
return(ret);
}
/* --设置事务为自动提交 */
ret = mysql_query( mysql, UNSET_TRAN ); /* "set autocommit = 1" */
if ( ret != 0 )
{
printf( "mysql_AutoTran query set err: %s\n", mysql_error( mysql ) );
return(ret);
}
return(ret);
}
/* 执行commit,手动提交事务 */
int mysql_Commit( MYSQL *mysql )
{
int ret = mysql_query( mysql, "COMMIT" ); /* 提交 */
if ( ret != 0 )
{
printf( "commit err: %s\n", mysql_error( mysql ) );
return(ret);
}
return(ret);
}
/* 执行rollback,回滚事务 */
int mysql_Rollback( MYSQL *mysql )
{
int ret = mysql_query( mysql, "ROLLBACK" );
if ( ret != 0 )
{
printf( "rollback err: %s\n", mysql_error( mysql ) );
return(ret);
}
return(ret);
}
#define DROP_SAMPLE_TABLE "DROP TABLE IF EXISTS test_table"
#define CREATE_SAMPLE_TABLE "CREATE TABLE test_table(col1 INT,\
col2 VARCHAR(10),\
col3 VARCHAR(10))"
#define sql01 "INSERT INTO test_table(col1,col2,col3) VALUES(10, 'AAA', 'A1')"
#define sql02 "INSERT INTO test_table(col1,col2,col3) VALUES(20, 'BBB', 'B2')"
#define sql03 "INSERT INTO test_table(col1,col2,col3) VALUES(30, 'CCC', 'C3')"
#define sql04 "INSERT INTO test_table(col1,col2,col3) VALUES(40, 'DDD', 'D4')"
int main( void )
{
int ret = 0;
MYSQL *mysql = mysql_init( NULL );
mysql = mysql_real_connect( mysql, _HOST_, _USER_, _PASSWD_, _DBNAME_, 0, NULL, 0 );
if ( mysql == NULL )
{
ret = mysql_errno( mysql );
printf( "func mysql_real_connect() err:%d\n", ret );
return(ret);
}
printf( " --- connect ok......\n" );
/* 执行删除表 */
if ( mysql_query( mysql, DROP_SAMPLE_TABLE ) )
{
fprintf( stderr, " DROP TABLE failed\n" );
fprintf( stderr, " %s\n", mysql_error( mysql ) );
exit( 0 );
}
/* 执行创建表 */
if ( mysql_query( mysql, CREATE_SAMPLE_TABLE ) )
{
fprintf( stderr, " CREATE TABLE failed\n" );
fprintf( stderr, " %s\n", mysql_error( mysql ) );
exit( 0 );
}
ret = mysql_OperationTran( mysql ); /* 开启事务,并修改事务属性为手动commit */
if ( ret != 0 )
{
printf( "mysql_OperationTran() err:%d\n", ret );
return(ret);
}
ret = mysql_query( mysql, sql01 ); /* 向表中插入第一行数据 ‘AAA’ */
if ( ret != 0 )
{
printf( "mysql_query() err:%d\n", ret );
return(ret);
}
ret = mysql_query( mysql, sql02 ); /* 向表中插入第二行数据 ‘BBB’ */
if ( ret != 0 )
{
printf( "mysql_query() err:%d\n", ret );
return(ret);
}
ret = mysql_Commit( mysql ); /* 手动提交事务 */
if ( ret != 0 )
{
printf( "mysql_Commit() err:%d\n", ret );
return(ret);
}
/* ////////AAA BBB 进去了。 */
#if 1
ret = mysql_AutoTran( mysql ); /* =再次= 修改事务属性为【自动】commit */
if ( ret != 0 )
{
printf( "mysql_OperationTran() err:%d\n", ret );
return(ret);
}
#else
ret = mysql_OperationTran( mysql ); /* =再次= 修改事务属性为【手动】commit */
if ( ret != 0 )
{
printf( "mysql_OperationTran() err:%d\n", ret );
return(ret);
}
#endif
ret = mysql_query( mysql, sql03 ); /* 向表中插入第三行数据 ‘CCC’ */
if ( ret != 0 )
{
printf( "mysql_query() err:%d\n", ret );
return(ret);
}
ret = mysql_query( mysql, sql04 ); /* 向表中插入第四行数据 ‘DDD’ */
if ( ret != 0 )
{
printf( "mysql_query() err:%d\n", ret );
return(ret);
}
ret = mysql_Rollback( mysql ); /* 直接rollback操作 */
if ( ret != 0 )
{
printf( "mysql_Rollback() err:%d\n", ret );
return(ret);
}
/* rollback操作是否能回退掉CCC、DDD的值,取决于事务属性。 */
mysql_close( mysql );
return(0);
}
5 增删改查
5.1 增
使用预处理
strSql = "insert into IMUser(`salt`,`sex`,`nick`,`password`,`domain`,`name`,`phone`,`email`,`company`,`address`,`avatar`,`sign_info`,`departId`,`status`,`created`,`updated`) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
5.2 删
5.3 改
-更新,直接sql语句更新
mysql_real_query
范例
string str_sql = "update IMUser set `sign_info`='" + sign_info + "', `updated`=" + int2string(now) + " where id="+int2string(user_id);
bool CDBConn::ExecuteUpdate( const char* sql_query, bool care_affected_rows )
{
mysql_ping( m_mysql );
if ( mysql_real_query( m_mysql, sql_query, strlen( sql_query ) ) )
{
log_error( "mysql_real_query failed: %s, sql: %s", mysql_error( m_mysql ), sql_query );
/* g_master_conn_fail_num ++; */
return(false);
}
if ( mysql_affected_rows( m_mysql ) > 0 )
{
return(true);
}else { /* 影响的行数为0时 */
if ( care_affected_rows ) /* 如果在意影响的行数时, 返回false, 否则返回true */
{
log_error( "mysql_real_query failed: %s, sql: %s", mysql_error( m_mysql ), sql_query );
return(false);
}else {
log_warn( "affected_rows=0, sql: %s", sql_query );
return(true);
}
}
}
5.4 查
enum enum_field_types {
MYSQL_TYPE_DECIMAL,
MYSQL_TYPE_TINY,
MYSQL_TYPE_SHORT,
MYSQL_TYPE_LONG,
MYSQL_TYPE_FLOAT,
MYSQL_TYPE_DOUBLE,
MYSQL_TYPE_NULL,
MYSQL_TYPE_TIMESTAMP,
MYSQL_TYPE_LONGLONG,
MYSQL_TYPE_INT24,
MYSQL_TYPE_DATE,
MYSQL_TYPE_TIME,
MYSQL_TYPE_DATETIME,
MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE,
MYSQL_TYPE_VARCHAR,
MYSQL_TYPE_BIT,
MYSQL_TYPE_TIMESTAMP2,
MYSQL_TYPE_DATETIME2,
MYSQL_TYPE_TIME2,
MYSQL_TYPE_NEWDECIMAL=246,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
MYSQL_TYPE_TINY_BLOB=249,
MYSQL_TYPE_MEDIUM_BLOB=250,
MYSQL_TYPE_LONG_BLOB=251,
MYSQL_TYPE_BLOB=252,
MYSQL_TYPE_VAR_STRING=253,
MYSQL_TYPE_STRING=254,
MYSQL_TYPE_GEOMETRY=255
}
typedef struct st_mysql_field {
char *name; /* Name of column 列名 */
char *org_name; /* Original column name, if an alias */
char *table; /* Table of column if column was a field */
char *org_table; /* Org table name, if table was an alias */
char *db; /* Database for table */
char *catalog; /* Catalog for table */
char *def; /* Default value (set by mysql_list_fields) */
unsigned long length; /* Width of column (create length) */
unsigned long max_length; /* Max width for selected set */
unsigned int name_length;
unsigned int org_name_length;
unsigned int table_length;
unsigned int org_table_length;
unsigned int db_length;
unsigned int catalog_length;
unsigned int def_length;
unsigned int flags; /* Div flags */
unsigned int decimals; /* Number of decimals in field */
unsigned int charsetnr; /* Character set */
enum enum_field_types type; /* Type of field. See mysql_com.h for types */ // 字段的mysql 数据类型
void *extension;
} MYSQL_FIELD;
int mysql_real_query(MYSQL *mysql, const char *q, unsigned long length);
说明:执行SQL
参数1:已初始化的MYSQL 实例;
参数2:SQL 语句;
参数3:SQL 语句字符数。
MYSQL_RES *mysql_store_result(MYSQL *mysql);
说明:对于成功检索了数据的每个查询(SELECT、SHOW、DESCRIBE、EXPLAIN、CHECK TABLE等),
必须调用mysql_store_result()或mysql_use_result()
参数:已初始化的MYSQL 实例。
// typedef char **MYSQL_ROW;
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
说明:检索一个结果集合的下一行。当在mysql_store_result()之后使用时,
如果没有更多的行可检索时,mysql_fetch_row()返回NULL。当在mysql_use_result()之后使用时,
当没有更多的行可检索时或如果出现一个错误,mysql_fetch_row()返回NULL。