一、源代码说明
freecplus是一个Linux系统下的C/C++开源框架,源代码请前往C语言技术网(www.freecplus.net )下载。
本文介绍的是freecplus框架中采用connection和sqlstatement类操作MySQL数据库。
类的声明文件是freecplus/db/mysql/_mysql.h。
类的定义文件是freecplus/db/mysql/_mysql.cpp。
示例程序位于freecplus/db/mysql目录中。
编译规则文件是freecplus/db/mysql/makefile。
二、概述
本文不会介绍MySQL数据库、SQL语言和C/C的基础知识,您应该是一个职业的C/C 程序员,在阅读本文之前,您已经掌握了MySQL数据库和SQL语言的基础知识。
freecplus框架把MySQL提供的库函数封装成了connection和sqlstatement类,采用封装后的类操作MySQL数据库,代码简洁优雅,性能卓越。
接下来我先列出connection和sqlstatement类的声明,然后通过流程图和示例程序介绍它位的用法。
三、connection类
MySQL数据库连接connection类的声明(程序员不必关心的私有成员和数据结构未列出):
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 class connection { public : int m_state; CDA_DEF m_cda; char m_sql[10241 ]; connection (); ~connection (); int connecttodb (char *connstr,char *charset,unsigned int autocommitopt=0 ) ; int commit () ; int rollback () ; int disconnect () ; int execute (const char *fmt,...) ; };
四、sqlstatement类
MySQL数据库的SQL语句操作sqlstatement类的声明(程序员不必关心的私有成员和数据结构未列出):
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 class sqlstatement { public : int m_state; char m_sql[10241 ]; CDA_DEF m_cda; sqlstatement (); sqlstatement (connection *conn); ~sqlstatement (); int connect (connection *conn) ; int disconnect () ; int prepare (const char *fmt,...) ; int bindin (unsigned int position,int *value) ; int bindin (unsigned int position,long *value) ; int bindin (unsigned int position,unsigned int *value) ; int bindin (unsigned int position,unsigned long *value) ; int bindin (unsigned int position,float *value) ; int bindin (unsigned int position,double *value) ; int bindin (unsigned int position,char *value,unsigned int len) ; int bindout (unsigned int position,int *value) ; int bindout (unsigned int position,long *value) ; int bindout (unsigned int position,unsigned int *value) ; int bindout (unsigned int position,unsigned long *value) ; int bindout (unsigned int position,float *value) ; int bindout (unsigned int position,double *value) ; int bindout (unsigned int position,char *value,unsigned int len) ; int execute () ; int execute (const char *fmt,...) ; int next () ; };
五、程序流程
freecplus框架把对MySQL数据库操作的SQL语句分为两种:有结果集的SQL语句和无结果集的SQL语句。
如果SQL语句被执行后,有结果集的产生,称为有结果集的SQL,即数据查询语言DQL,以select关键字,各种简单查询,连接查询等都属于DQL。
如果SQL语句被执行后,没有结果集的产生,称为无结果集的SQL,包括数据定义语言DDL(主要是create、drop和alter)和数据操纵语言DML(insert、update和insert)。
也可以这么说,查询的SQL语句会产生结果集,其它的SQL语句不会产生结果集。
1、无结果集SQL的程序的流程
这是一个完程的流程,在实际开发中,如果是执行简单的SQL语句,第6步和第7步可能不需要,如果SQL语句只执行一次,第7步和第8步之间的循环也不需要。
2、有结果集SQL的程序的流程
这是一个完程的流程,在实际开发中,如果是执行简单的查询语句,第6步、第7步和第8步可能不需要,如果结果集中最多只有一条记录,第10步和第11步之间的循环也不需要。
六、示例程序
1、创建超女信息表
示例(createtable.cpp)
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 #include "_mysql.h" int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("172.16.0.15,root,123qweASD!@#,mysql,3306" ,"gbk" ) != 0 ) { printf ("connect database failed.\n%s\n" ,conn.m_cda.message); return -1 ; } sqlstatement stmt (&conn) ; stmt.prepare ("\ create table girls(id bigint(10),\ name varchar(30),\ weight decimal(8,2),\ btime datetime,\ memo longtext,\ pic longblob,\ primary key (id))" ); if (stmt.execute () != 0 ) { printf ("stmt.execute() failed.\n%s\n%s\n" ,stmt.m_sql,stmt.m_cda.message); return -1 ; } printf ("create table girls ok.\n" ); }
运行效果
2、向超女表中插入5条记录
示例(inserttable.cpp)
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 #include "_mysql.h" struct st_girls { long id; char name[11 ]; double weight; char btime[20 ]; } stgirls; int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("172.16.0.15,root,123qweASD!@#,mysql,3306" ,"gbk" ) != 0 ) { printf ("connect database failed.\n%s\n" ,conn.m_cda.message); return -1 ; } sqlstatement stmt (&conn) ; stmt.prepare ("\ insert into girls(id,name,weight,btime) \ values(:1,:2,:3,str_to_date(:4,'%%Y-%%m-%%d %%h:%%i:%%s'))" ); stmt.bindin (1 ,&stgirls.id); stmt.bindin (2 , stgirls.name,10 ); stmt.bindin (3 ,&stgirls.weight); stmt.bindin (4 , stgirls.btime,19 ); for (int ii=1 ;ii<=5 ;ii++) { memset (&stgirls,0 ,sizeof (stgirls)); stgirls.id=ii; sprintf (stgirls.name,"超女%02d" ,ii); stgirls.weight=ii*2.11 ; strcpy (stgirls.btime,"2018-03-01 12:25:31" ); if (stmt.execute () != 0 ) { printf ("stmt.execute() failed.\n%s\n%s\n" ,stmt.m_sql,stmt.m_cda.message); return -1 ; } printf ("成功插入了%ld条记录。\n" ,stmt.m_cda.rpc); } printf ("insert table girls ok.\n" ); conn.commit (); }
运行效果
3、更新超女表中的记录
示例(updatetable.cpp)
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 #include "_mysql.h" int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("172.16.0.15,root,123qweASD!@#,mysql,3306" ,"gbk" ) != 0 ) { printf ("connect database failed.\n%s\n" ,conn.m_cda.message); return -1 ; } sqlstatement stmt (&conn) ; char strbtime[20 ]; memset (strbtime,0 ,sizeof (strbtime)); strcpy (strbtime,"2019-12-20 09:45:30" ); stmt.prepare ("\ update girls set btime=str_to_date(:1,'%%Y-%%m-%%d %%h:%%i:%%s') where id>=2 and id<=4" ); stmt.bindin (1 ,strbtime,19 ); if (stmt.execute () != 0 ) { printf ("stmt.execute() failed.\n%s\n%s\n" ,stmt.m_sql,stmt.m_cda.message); return -1 ; } printf ("本次更新了girls表%ld条记录。\n" ,stmt.m_cda.rpc); conn.commit (); }
运行效果
4、查询超女表中的记录
示例(selecttable.cpp)
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 #include "_mysql.h" struct st_girls { long id; char name[31 ]; double weight; char btime[20 ]; } stgirls; int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("172.16.0.15,root,123qweASD!@#,mysql,3306" ,"gbk" ) != 0 ) { printf ("connect database failed.\n%s\n" ,conn.m_cda.message); return -1 ; } sqlstatement stmt (&conn) ; int iminid,imaxid; stmt.prepare ("\ select id,name,weight,date_format(btime,'%%Y-%%m-%%d %%h:%%i:%%s') from girls where id>=:1 and id<=:2" ); stmt.bindin (1 ,&iminid); stmt.bindin (2 ,&imaxid); stmt.bindout (1 ,&stgirls.id); stmt.bindout (2 , stgirls.name,30 ); stmt.bindout (3 ,&stgirls.weight); stmt.bindout (4 , stgirls.btime,19 ); iminid=2 ; imaxid=4 ; if (stmt.execute () != 0 ) { printf ("stmt.execute() failed.\n%s\n%s\n" ,stmt.m_sql,stmt.m_cda.message); return -1 ; } while (1 ) { memset (&stgirls,0 ,sizeof (stgirls)); if (stmt.next () !=0 ) break ; printf ("id=%ld,name=%s,weight=%.02f,btime=%s\n" ,stgirls.id,stgirls.name,stgirls.weight,stgirls.btime); } printf ("本次查询了girls表%ld条记录。\n" ,stmt.m_cda.rpc); }
运行效果
5、查询超女表中的记录数
示例(counttable.cpp)
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 #include "_mysql.h" int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("172.16.0.15,root,123qweASD!@#,mysql,3306" ,"gbk" ) != 0 ) { printf ("connect database failed.\n%s\n" ,conn.m_cda.message); return -1 ; } sqlstatement stmt (&conn) ; int icount=0 ; stmt.prepare ("select count(*) from girls where id>=2 and id<=4" ); stmt.bindout (1 ,&icount); if (stmt.execute () != 0 ) { printf ("stmt.execute() failed.\n%s\n%s\n" ,stmt.m_sql,stmt.m_cda.message); return -1 ; } stmt.next (); printf ("girls表中符合条件的记录数是%d。\n" ,icount); }
运行效果
7、删除超女表中的记录
示例(deletetable.cpp)
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 #include "_mysql.h" int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("172.16.0.15,root,123qweASD!@#,mysql,3306" ,"gbk" ) != 0 ) { printf ("connect database failed.\n%s\n" ,conn.m_cda.message); return -1 ; } sqlstatement stmt (&conn) ; if (stmt.execute ("delete from girls where id>=2 and id<=4" ) != 0 ) { printf ("stmt.execute() failed.\n%s\n%s\n" ,stmt.m_sql,stmt.m_cda.message); return -1 ; } printf ("本次从girls表中删除了%ld条记录。\n" ,stmt.m_cda.rpc); conn.commit (); }
运行效果
8、与Oracle的兼容性处理
在封装sqlstatement类的时候,为了与Oracle兼容,做了以下方面的处理:
1)在MySQL中,绑定输入和输出变量采用的是"?“,Oracle采用的是”:n"(n表示变量的序号),在sqlstatement的prepare方法中,把":n"替换成了"?"。
2)在MySQL中,字符串与日期的转换函数是str_to_date和date_format,Oracle的转换函数是to_date和to_char,在sqlstatement的prepare方法中,把to_date替换成str_to_date,把to_char替换成date_format。
3)MySQL有时间格式是"%Y-%m-%d %h:%i:%s",Oracle数据库是"yyyy-mm-dd hh24:mi:ss",在sqlstatement的prepare方法中,把"yyyy-mm-dd hh24:mi:ss"替换成"%Y-%m-%d %h:%i:%s"。目前,只对"%Y-%m-%d %h:%i:%s"和"%Y%m%d%h%i%s"两个格式做了替换,如果需要对更多的格式做替换,请修改sqlstatement的prepare方法中的源代码。
4)MySQL的sqlstatement类绑定输入或输出变量的最大数量缺省是256,在"_mysql.h"头文件中定义了MAXPARAMS宏,您可以根据实际需求修改它。
9、longtext和longblob字段的操作
MySQL提供的库函数支持对longtext和longblob字段的操作,本人的技术水平有限,找不到这方面的资料和示例程序,所以还没有封装对longtext和longblob字段的操作,希望各位能提供技术帮助,通过C语言技术网与我联系,我们共同完善freecplus框架,非常感谢。
七、应用经验
本文提供的示例程序看上去简单,实则很精妙,希望大家多多思考,慢慢体会。
为了让大家完全掌握connection和sqlstatement类的用法,我将录制freecplus框架的专题视频,请大家多关注C语言技术网(www.freecplus.net )发布的内容。
八、版权声明
C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
来源:C语言技术网(www.freecplus.net )
作者:码农有道