MySQL C API的定义及使用方法

第一部分:init初始化MySQL连接的相关API:

(1) mysql_init :

MYSQL* mysql_init(MYSQL *mysql);

返回一个MYSQL 句柄,对应这个句柄MySQL会在数据库内部分配一个对象并开辟内存,用于存储关联这个连接的处理信息。
后续所有的对这条数据库连接的操作都是通过这个句柄,类似于socket()返回的sockfd。
如果MySQL内部内存不足,则返回NULL。

(2) mysql_options :

int mysql_options(MYSQL* mysql, enum mysql_option option, const void* arg);

设置额外的连接选项,用于控制连接行为。
mysql_init 之后、mysql_connect 之前 进行调用。
option 参数用于指定要设置的选项类型;
arg 参数用于设置此选项的值。
常用的选项有:
MYSQL_OPT_RECONNECT:当发现连接断开时,自动进行重连(例如超8小时无活动,连接被MySQL server断开后,再次进行访问时发现连接已断开,会自动进行重连)
MYSQL_SET_CHARSET_NAME:设置默认的charset

(3) mysql_real_connect :

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 server发起连接,后续所有的对数据库的操作都需要先建立连接。

>> Example 1: Init()初始化部分使用举例:

int CDBConn::Init() {
	m_mysql = mysql_init(NULL);
    if(!m_mysql) {
		return -1;
	}
	
    my_bool reconnect = true;
    mysql_options(m_mysql, MYSQL_OPT_RECONNECT, &reconnect);
    mysql_options(m_mysql, MYSQL_OPT_CHARSET_NAME, "utf8mb4");

	if(mysql_real_connect(m_mysql, m_pDBPool->GetDBServerIP(), m_pDBPool->GetUsername(), m_pDBPool->GetPassword(), 
			m_pDBPool->GetDBName(), m_pDBPool->GetDBServerPort(), NULL, 0) ) { 
	    return -1; 
	}

	return 0;
}

第二部分:执行“select”查询功能的API:

(4) mysql_ping :

int mysql_ping(MYSQL* mysql);

检查与MySQL的连接是否正常。如果连接已经断开,且已设置了自动重连 MYSQL_OPT_RECONNECT 选项,则发起自动重连;
如果没有开启自动重连选项,则返回error。

(5) mysql_real_query :

int mysql_real_query(MYSQL* mysql, const char* stmt_str, unsigned long length);

执行参数 stmt_str 传入的查询语句,其中不包含 “;” SQL语句结束符。

(6) mysql_store_result :

MYSQL_RES* mysql_store_result(MYSQL* msyql);

在调用 mysql_real_query 之后,必须 调用 mysql_store_result 用于存放查询结果。
且在使用完毕后,必须 调用 mysql_free_result 去释放 mysql_store_result 分配的内存(用于保存查询结果的内存)。

(7) mysql_free_result :

void mysql_free_result(MYSQL_RES *result);

用于释放前面 mysql_store_result 分配的内存。

>> Example 2: Select查询部分使用举例:

CResultSet* CDBConn::ExcuteQuery(const char* sql_query) {
    mysql_ping(m_mysql);
    
    if(mysql_real_query(m_mysql, sql_query, strlen(sql_query))) {
        printf("mysql_real_query failed: %s, sql: %s\n", mysql_error(m_mysql), sql_query);
        return NULL;
    }

	MYSQL_RES* res = mysql_store_result(m_mysql);
	if(!res) {
        printf("mysql_store_result failed: %s\n", mysql_error(m_mysql));
        return NULL;
    }
	//将查询到的结果MYSQL_RES封装成CResultSet对象返回给上级调用函数,待外层函数使用完毕后再调用 mysql_free_result 去释放这块内存
	CResultSet* result_set = new CResultSet(res);
	return result_set;
}

(8) mysql_num_fields :

unsigned int mysql_num_fields(MYSQL_RES* result);

返回查询结果集中的列的数目。

(9) mysql_fetch_fields :

MYSQL_FIELD* mysql_fetch_fields(MYSQL_RES* result);

返回查询结果集中所有 MYSQL_FIELD 结构的数组。数组中的每个结构体表示一个列的字段定义。“对一个列的属性描述”,包括列名、列数据类型等

(10) mysql_fetch_row :

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

检索查询结果集(MYSQL_RES) 中的下一行。
在 mysql_store_result 之后使用时,如果没有要检索的行,或者检索出错,mysql_fetch_row()返回NULL;
行内值的数据由 mysql_num_fields() 给出(即列的数目),可通过 row[column_index] 访问这些指针(从 row[0] 到 row[mysql_num_fields()-1])

>> Example 3: 解析查询MySQL查询结果举例:

//将mysql_store_result返回的MYSQL_RES查询结构进行解析、分解后,存储在CResultSet对象中:
class CResultSet {
public:
    CResultSet(MYSQL_RES* res);
    virtual ~CResultSet();
	
	bool Next();
	int GetInt(const char* key);
	char* GetString(const char* key);
private:
	int _GetIndex(const char* key);
private:
	MYSQL_RES*		  m_res;
	MYSQL_ROW		  m_row;
	map<string, int>  m_key_map;
};


第三部分:执行“增删改”(insert/delete/update)操作的API:

(11) mysql_affected_rows :

my_ulonglong  mysql_affected_rows(MYSQL *mysql);

返回上次UPDATE更改的行数,上次DELETE删除的行数,或者上次INSERT语句插入的行数。
对于UPDATE、DELETE、INSERT语句,可以在 msyql_query() 后立刻调用;
对于SELECT语句,mysql_affected_rows() 的工作方式与mysql_num_rows类似。

>> Example 4: 执行Update更新操作举例:

//例如 char* sql_query = "update [table_name] set [change_value] where [select_option];"
bool CDBConn::ExcuteUpdate(const char* sql_query) {
    mysql_ping(m_mysql);

    if(mysql_real_query(m_mysql, sql_query, strlen(sql_query))) {
        printf("mysql_real_query failed: %s\n", mysql_error(m_mysql));
        return false;
    }
    
    //使用msyql_affected_rows检查UPDATE等语句是否正确生效:
    if(mysql_affected_rows(m_mysql) > 0) {	
		return true;
	}
	else {
        return false;
    }
}

第四部分: PrepareStatement 防注入:

PrepareStatement主要是使用【预编译】防止SQL注入。
预编译语句就是将这类语句中的值用“占位符”(?) 替代,可以视为将sql语句“模板化”或者“参数化”。
一次编译,多次运行,省去了解析优化等过程。

预编译 的作用:
(1)预编译阶段可以优化sql的执行;
(2)防止SQL注入:
使用预编译,而其后注入的参数将不会再进行SQL编译,也就是说其后注入进来的参数将不会认为它是一条SQL语句,
而默认其是一个参数,参数中的 or 或者 and 等就不是SQL语句保留字了。

(12) mysql_stmt_init :

创建 MYSQL_STMT 句柄

MYSQL_STMT*  mysql_stmt_init(MYSQL *mysql);

描述: 创建 MYSQL_STMT 句柄。对于该句柄,应该用 mysql_stmt_close(MYSQL_STMT*); 释放。
返回值:成功时返回指向MYSQL_STMT结构的指针;失败时返回NULL。

(13) mysql_stmt_prepare :

作用相当于是注册一条带有“?”参数标记符 的SQL语句,这里应该就是【预编译】的操作

int  mysql_stmt_prepare(MYSQL_STMT* stmt, const char* query, unsigned long length);

入参:
给定mysql_stmt_init返回的MYSQL_STMT 句柄,以及待执行的SQL语句(字符串、字符串长度)。
通过将问号字符 “?” 嵌入到SQl字符串的恰当位置,应用程序可包含SQL语句中的一个或多个参数标记符。
标记符仅在SQL语句中的特定位置时才是合法的。
执行语句之前,必须使用 mysql_stmt_bind_param(),将“参数标记符”(?) 与 “应用程序变量” 绑定到一起。
(mysql_stmt_bind_param 相当于是一个传参的过程,?是形参,应用程序传入的变量是实参。)
使用举例:

mysql_stmt_prepare( m_stmt, sql.c_str(), sql.size() );

string sql = "insert into IMMessage_x (related, fromId, toId, msgId, content, status, type, created, updated) values (?,?,?,?,?,?,?,?,?)";

(14) mysql_stmt_param_count :

unsigned long  mysql_stmt_param_count(MYSQL_STMT* stmt);

返回预处理语句中参数标记符的数目。

(15) mysql_stmt_bind_param :

my_bool  mysql_stmt_bind_param(MYSQL_STMT* stmt, MYSQL_BIND* bind);

用于为SQL语句中的 “参数标记符”(?) 绑定数据(“实参”),以传递给 mysql_stmt_prepare中的?位置。
注入此函数需要使用 MYSQL_BIND* 为元素类型的数组进行入参,所以在调用函数之前需要先 new MYSQL_BIND[param_count] 构造一个数组。

(16) mysql_stmt_execute :

int  mysql_stmt_excute(MYSQL_STMT* stmt);

执行与语句相关的预处理查询。
将当前绑定的参数标记符的值发送给服务器,服务器用新提供的数据替换标记符。

如果语句是insert/update/delete(增删改),通过调用 mysql_stmt_affected_rows() 确认更改/插入/删除的总行数;
如果语句是 select,则需要调用 msyql_stmt_fetch() 来获取数据。

(17) mysql_stmt_affected_rows :

my_ulonglong  mysql_stmt_affected_rows(MYSQL_STMT* stmt);

返回上次执行语句更改、删除或插入的总行数。

(18) mysql_stmt_fetch :

同mysql_fetch_row / mysql_fetch_fields 的用法。

(19) mysql_stmt_insert_id :

my_ulonglong  mysql_stmt_insert_id(MYSQL_STMT* stmt);

返回预处理“INSERT”或者“UPDATE” 语句为 AUTO_INCREMENT列生成的值。
在包含
也就是说,如果一个表中有某个列的属性是AUTO_INCREMENT自增的,那么当对这个表进行一次INSERT或者UPDATE后,
调用mysql_stmt_insert_id()这个函数就可以得到INSERT操作新增的行元素的自增一列的值。

>> Example 5: 使用预编译防止SQL注入举例:

待补充。。。。。。







MYSQL_STMT* m_stmt = mysql_stmt_init(MYSQL* m_mysql);
mysql_stmt_prepare(m_stmt, sql.c_str(), sql.size());	//sql="insert into ... values (???)"
	mysql_stmt_param_count(m_stmt);	//只是一个安全校验
MYSQL_BIND* m_param_bind = new MYSQL_BIND[m_param_cnt];		//new一块堆内存

m_param_bind[index].buffer_type 	= MYSQL_TYPE_STRING;
m_param_bind[index].buffer			= (char*)value.c_str();
m_param_bind[index].buffer_length	= value.size();
/*
m_param_bind[index].buffer_type		= MYSQL_TYPE_LONG;
m_param_bind[index].buffer			= &value;
*/

mysql_stmt_bind_param(m_stmt, m_param_bind);
mysql_stmt_excute(m_stmt);
mysql_stmt_affected_rows();	/ mysql_stmt_fetch_fields();

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值