您好,登錄后才能下訂單哦!
本文主要給大家介紹MySQL C API執(zhí)行SQL語句的一種方式,其所涉及的東西,從理論知識(shí)來獲悉,有很多書籍、文獻(xiàn)可供大家參考,從現(xiàn)實(shí)意義角度出發(fā),億速云累計(jì)多年的實(shí)踐經(jīng)驗(yàn)可分享給大家。
接著看
預(yù)處理語句(Prepared Statements)
MySQL C API還提供了另一種方式來執(zhí)行SQL語句,即先預(yù)處理(prepare)再執(zhí)行
(execute). 對(duì)于多次執(zhí)行的SQL語句,該方式可以提高其執(zhí)行效率。具體步驟如下:
MYSQL_STMT mysql_stmt_init(MYSQL mysql)
描述
創(chuàng)建MYSQL_STMT句柄。對(duì)于該句柄,應(yīng)使用mysql_stmt_close(MYSQL_STMT *)釋放。
返回值
成功時(shí),返回指向MYSQL_STMT結(jié)構(gòu)的指針。如果內(nèi)存溢出,返回NULL。
錯(cuò)誤
· CR_OUT_OF_MEMORY
內(nèi)存溢出。
調(diào)用mysql_stmt_prepare()對(duì)SQL語句進(jìn)行預(yù)處理
int mysql_stmt_prepare(MYSQL_STMT stmt, const char stmt_str, unsigned long length)
int mysql_stmt_prepare(MYSQL_STMT stmt, const char query, unsigned long length)
描述
給定mysql_stmt_init()返回的語句句柄,準(zhǔn)備字符串查詢指向的SQL語句,并返回狀態(tài)值。字符串長(zhǎng)度應(yīng)由“l(fā)ength”參量給出。字符串必須包含1條SQL語句。不應(yīng)為語句添加終結(jié)用分號(hào)(‘;’)或\g。
通過將問號(hào)字符“?”嵌入到SQL字符串的恰當(dāng)位置,應(yīng)用程序可包含SQL語句中的一個(gè)或多個(gè)參數(shù)標(biāo)記符。
標(biāo)記符僅在SQL語句中的特定位置時(shí)才是合法的。例如,它可以在INSERT語句的VALUES()列表中(為行指定列值),或與WHERE子句中某列的比較部分(用以指定比較值)。但是,對(duì)于ID(例如表名或列名),不允許使用它們,不允許指定二進(jìn)制操作符(如等于號(hào)“=”)的操作數(shù)。后一個(gè)限制是有必要的,原因在于,無法確定參數(shù)類型。一般而言,參數(shù)僅在DML(數(shù)據(jù)操作語言)語句中才是合法的,在DDL(數(shù)據(jù)定義語言)語句中不合法。
執(zhí)行語句之前,必須使用mysql_stmt_bind_param(),將參數(shù)標(biāo)記符與應(yīng)用程序變量綁定在一起。
返回值
如果成功處理了語句,返回0。如果出現(xiàn)錯(cuò)誤,返回非0值。
my_bool mysql_stmt_bind_param(MYSQL_STMT stmt, MYSQL_BIND bind)
描述
mysql_stmt_bind_param()用于為SQL語句中的參數(shù)標(biāo)記符綁定數(shù)據(jù),以傳遞給mysql_stmt_prepare()。它使用MYSQL_BIND結(jié)構(gòu)來提供數(shù)據(jù)?!癰ind”是MYSQL_BIND結(jié)構(gòu)的某一數(shù)組的地址。按照客戶端庫(kù)的預(yù)期,對(duì)于查詢中出現(xiàn)的每個(gè)“?”參數(shù)標(biāo)記符,數(shù)組中均包含1個(gè)元素。
假定你準(zhǔn)備了下述語句:
INSERT INTO mytbl VALUES(?,?,?)
綁定參數(shù)時(shí),MYSQL_BIND結(jié)構(gòu)的數(shù)組包含3個(gè)元素,并能聲明如下:
MYSQL_BIND bind[3];
返回值
如果綁定成功,返回0。如果出現(xiàn)錯(cuò)誤,返回非0值。
int mysql_stmt_execute(MYSQL_STMT *stmt)
描述
mysql_stmt_execute()執(zhí)行與語句句柄相關(guān)的預(yù)處理查詢。在該調(diào)用期間,將當(dāng)前綁定的參數(shù)標(biāo)記符的值發(fā)送到服務(wù)器,服務(wù)器用新提供的數(shù)據(jù)替換標(biāo)記符。
如果語句是UPDATE、DELETE或INSERT,通過調(diào)用mysql_stmt_affected_rows(),可發(fā)現(xiàn)更改、刪除或插入的總行數(shù)。如果這是諸如SELECT等能生成結(jié)果集的語句,調(diào)用任何其他能導(dǎo)致查詢處理的函數(shù)之前,必須調(diào)用mysql_stmt_fetch()來獲取數(shù)據(jù)。
對(duì)于生成結(jié)果集的語句,執(zhí)行語句之前,可通過調(diào)用mysql_stmt_attr_set(),請(qǐng)求mysql_stmt_execute()為語句打開光標(biāo)。如果多次執(zhí)行某一語句,在打開新的光標(biāo)前,mysql_stmt_execute()將關(guān)閉任何已打開的光標(biāo)。
返回值
如果執(zhí)行成功,返回0。如果出現(xiàn)錯(cuò)誤,返回非0值。
my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT *stmt)
描述
返回上次執(zhí)行語句更改、刪除或插入的總行數(shù)。對(duì)于UPDATE、DELETE或INSERT語句,可在mysql_stmt_execute()之后立刻調(diào)用它們。對(duì)于SELECT語句,mysql_stmt_affected_rows()的工作方式類似于mysql_num_rows()。
返回值
大于0的整數(shù)指明了受影響或檢索的行數(shù)。對(duì)于UPDATE語句,“0”表明未更新任何記錄,在查詢中沒有與WHERE子句匹配的行,或尚未執(zhí)行任何查詢?!?1”表明返回了錯(cuò)誤,或?qū)ELECT查詢,在調(diào)用mysql_stmt_store_result()之前調(diào)用了mysql_stmt_affected_rows()。由于mysql_stmt_affected_rows()返回?zé)o符號(hào)值,可通過比較返回值和“(my_ulonglong)-1”(或等效的“(my_ulonglong)~0”),檢查“-1”。
int mysql_stmt_store_result(MYSQL_STMT *stmt)
描述
對(duì)于成功生成結(jié)果集的所有語句(SELECT、SHOW、DESCRIBE、EXPLAIN),而且僅當(dāng)你打算對(duì)客戶端的全部結(jié)果集進(jìn)行緩沖處理時(shí),必須調(diào)用mysql_stmt_store_result(),以便后續(xù)的mysql_stmt_fetch()調(diào)用能返回緩沖數(shù)據(jù)。
對(duì)于其他語句,沒有必要調(diào)用mysql_stmt_store_result(),但如果調(diào)用了它,也不會(huì)造成任何傷害或?qū)е氯魏涡阅軉栴}。通過檢查mysql_stmt_result_metadata()是否返回NULL,可檢測(cè)語句是否生成了結(jié)果集。
返回值
如果成功完成了對(duì)結(jié)果的緩沖處理,返回0。如果出現(xiàn)錯(cuò)誤,返回非0值。
總體而言:
MySQL客戶端/服務(wù)器協(xié)議提供了預(yù)處理語句。該功能采用了由mysql_stmt_init()初始化函數(shù)返回的MYSQL_STMT語句處理程序數(shù)據(jù)結(jié)構(gòu)。對(duì)于多次執(zhí)行的語句,預(yù)處理執(zhí)行是一種有效的方式。首先對(duì)語句進(jìn)行解析,為執(zhí)行作好準(zhǔn)備。接下來,在以后使用初始化函數(shù)返回的語句句柄執(zhí)行一次或多次。
對(duì)于多次執(zhí)行的語句,預(yù)處理執(zhí)行比直接執(zhí)行快,主要原因在于,僅對(duì)查詢執(zhí)行一次解析操作。在直接執(zhí)行的情況下,每次執(zhí)行語句時(shí),均將進(jìn)行查詢。此外,由于每次執(zhí)行預(yù)處理語句時(shí)僅需發(fā)送參數(shù)的數(shù)據(jù),從而減少了網(wǎng)絡(luò)通信量。
預(yù)處理語句的另一個(gè)優(yōu)點(diǎn)是,它采用了二進(jìn)制協(xié)議,從而使得客戶端和服務(wù)器之間的數(shù)據(jù)傳輸更有效率。
編程步驟
?1. 用mysql_stmt_init()創(chuàng)建預(yù)處理語句句柄。要想在服務(wù)器上準(zhǔn)備預(yù)處理語句,可調(diào)用mysql_stmt_prepare(),并為其傳遞包含SQL語句的字符串
?2. 如果語句生成了結(jié)果集,調(diào)用mysql_stmt_result_metadata()以獲得結(jié)果集元數(shù)據(jù)。雖然與包含查詢返回列的結(jié)果集不同,該元數(shù)據(jù)本身也采用了結(jié)果集的形式。元數(shù)據(jù)結(jié)果集指明了結(jié)果中包含多少列,并包含每一列的信息。
?3. 使用mysql_stmt_bind_param()設(shè)置任何參數(shù)的值。必須設(shè)置所有參數(shù)。否則,語句執(zhí)行將返回錯(cuò)誤,或生成無法預(yù)料的結(jié)果。
?4. 調(diào)用mysql_stmt_execute()執(zhí)行語句。
?5. 如果語句生成了結(jié)果集,捆綁數(shù)據(jù)緩沖,通過調(diào)用mysql_stmt_bind_result(),檢索行值。
?6. 通過重復(fù)調(diào)用mysql_stmt_fetch(),按行將數(shù)據(jù)提取到緩沖區(qū),直至未發(fā)現(xiàn)更多行為止。
?7. 通過更改參數(shù)值并再次執(zhí)行語句,重復(fù)步驟3到步驟6。
實(shí)現(xiàn)代碼:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mysql/mysql.h>
#define STRING_SIZE 50
#define DROP_SAMPLE_TABLE "DROP TABLE IF EXISTS test_table"
#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(?,?,?)"
//int main(char *argv, int argc)
int main(char argv[], int argc)
{
int ret = 0, i = 0;
MYSQL *mysql;
MYSQL *connect = NULL;
char sqlbuf[2048];
mysql = mysql_init(NULL) ;
if (mysql == NULL)
{
ret = mysql_errno(&mysql) ;
printf("func mysql_init() err \n");
return ret;
}
printf("func mysql_init() ok \n");
connect = mysql_real_connect(mysql, "localhost", "root", "123456", "mydb2", 0, NULL, 0);
if (connect == NULL)
{
ret = mysql_errno(&mysql) ;
printf("func mysql_init() err \n");
return ret;
}
printf("func mysql_real_connect() ok \n");
MYSQL_STMT *stmt;
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); //初始化預(yù)處理環(huán)境句柄 MYSQL_STMT *stmt
if (!stmt)
{
fprintf(stderr, " mysql_stmt_init(), out of memory\n");
exit(0);
}
if (mysql_stmt_prepare(stmt, INSERT_SAMPLE, strlen(INSERT_SAMPLE))) //向預(yù)處理環(huán)境句柄stmt 中添加sql( 帶有占位符)
{
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); //獲取sql語言中 占位符 的個(gè)數(shù)
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; //設(shè)置第一個(gè)占位符的屬性
bind[0].buffer= (char *)&int_data;
bind[0].is_null= 0;
bind[0].length= 0;
/* STRING PARAM */
bind[1].buffer_type= MYSQL_TYPE_STRING; //設(shè)置第2個(gè)占位符的屬性
bind[1].buffer= (char *)str_data;
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; //設(shè)置第3個(gè)占位符的屬性
bind[2].buffer= (char *)&small_data;
bind[2].is_null= &is_null;
bind[2].length= 0;
/* Bind the buffers */
if (mysql_stmt_bind_param(stmt, bind)) //把設(shè)置好的屬性 加入預(yù)處理環(huán)境stmt中
{
fprintf(stderr, " mysql_stmt_bind_param() failed\n");
fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
exit(0);
}
/* Specify the data values for the first row */ //準(zhǔn)備插入數(shù)據(jù)
int_data= 10; /* integer */
strncpy(str_data, "MySQL", STRING_SIZE); /* string */
str_length= strlen(str_data);
/* INSERT SMALLINT data as NULL */
is_null= 1;
/* Execute the INSERT statement - 1*/
if (mysql_stmt_execute(stmt)) //執(zhí)行預(yù)處理環(huán)境 插入第一條記錄
{
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);
}
/* Specify data values for second row, then re-execute the statement */
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= 0; /* reset */
/* 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);
}
mysql_close(connect);
printf("hello...\n");
return ret;
看了以上MySQL C API執(zhí)行SQL語句的一種方式介紹,希望能給大家在實(shí)際運(yùn)用中帶來一定的幫助。本文由于篇幅有限,難免會(huì)有不足和需要補(bǔ)充的地方,大家可以繼續(xù)關(guān)注億速云行業(yè)資訊板塊,會(huì)定期給大家更新行業(yè)新聞和知識(shí),如有需要更加專業(yè)的解答,可在官網(wǎng)聯(lián)系我們的24小時(shí)售前售后,隨時(shí)幫您解答問題的。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。