一、源代码说明
freecplus是一个Linux系统下的C/C++开源框架,源代码请前往C语言技术网(www.freecplus.net )下载。
本文介绍的是freecplus框架中采用connection和sqlstatement类操作Oracle数据库。
类的声明文件是freecplus/db/oracle/_ooci.h。
类的定义文件是freecplus/db/oracle/_ooci.cpp。
示例程序位于freecplus/db/oracle目录中。
编译规则文件是freecplus/db/oracle/makefile。
二、概述
本文不会介绍Oracle数据库、SQL语言和C/C的基础知识,您应该是一个职业的C/C 程序员,在阅读本文之前,您已经掌握了Oracle数据库和SQL语言的基础知识。
Oracle数据库功能强大,性能卓越,无与伦比,并提供了数据访问接口OCI,OCI非常强大,强大到了普通C/C++程序员难以驾驭。
freecplus框架把OCI(Oracle Call Interface)封装成了connection和sqlstatement类,采用封装后的类操作Oracle数据库,代码简洁优雅,性能卓越。
接下来我先列出connection和sqlstatement类的声明,然后通过流程图和示例程序介绍它位的用法。
三、connection类
Oracle数据库连接池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,int autocommitopt=0 ) ; int commit () ; int rollback () ; int disconnect () ; int execute (const char *fmt,...) ; };
四、sqlstatement类
Oracle数据库的SQL语句操作sqlstatement类的声明(程序员不必关心的私有成员和数据结构未列出,对CLOB和BLOB字段操作的方法也未列出):
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 83 84 85 86 87 88 89 90 91 92 93 94 class sqlstatement { OCI_HANDLE m_handle; connection *m_conn; int m_sqltype; int m_autocommitopt; void err_report () ; OCILobLocator *m_lob; int alloclob () ; int filetolob (FILE *fp) ; int lobtofile (FILE *fp) ; void freelob () ; 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框架把对Oracle数据库操作的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 "_ooci.h" int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("scott/tiger@snorcl11g_198" ,"Simplified Chinese_China.ZHS16GBK" )!=0 ) { printf ("connect database failed.\n%s\n" ,conn.m_cda.message); return -1 ; } sqlstatement stmt (&conn) ; stmt.prepare ("\ create table girls(id number(10),\ name varchar2(30),\ weight number(8,2),\ btime date,\ memo clob,\ pic blob,\ 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 #include "_ooci.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 ("scott/tiger@snorcl11g_198" ,"Simplified Chinese_China.ZHS16GBK" )!=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,to_date(:4,'yyyy-mm-dd hh24:mi:ss'))" ); 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 #include "_ooci.h" int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("scott/tiger@snorcl11g_198" ,"Simplified Chinese_China.ZHS16GBK" )!=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=to_date(:1,'yyyy-mm-dd hh24:mi:ss') 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 #include "_ooci.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 ("scott/tiger@snorcl11g_198" ,"Simplified Chinese_China.ZHS16GBK" )!=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,to_char(btime,'yyyy-mm-dd hh24:mi:ss') 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 "_ooci.h" int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("scott/tiger@snorcl11g_198" ,"Simplified Chinese_China.ZHS16GBK" )!=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 "_ooci.h" int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("scott/tiger@snorcl11g_198" ,"Simplified Chinese_China.ZHS16GBK" )!=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、执行PL/SQL过程
示例(execplsql.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 "_ooci.h" int main (int argc,char *argv[]) { connection conn; if (conn.connecttodb ("scott/tiger@snorcl11g_198" ,"Simplified Chinese_China.ZHS16GBK" )!=0 ) { printf ("connect database failed.\n%s\n" ,conn.m_cda.message); return -1 ; } sqlstatement stmt (&conn) ; int id=100 ; stmt.prepare ("\ BEGIN\ delete from girls;\ insert into girls(id,name,weight,btime)\ values(:1,'超女过程',55.65,to_date('2018-01-02 13:00:55','yyyy-mm-dd hh24:mi:ss'));\ END;" ); stmt.bindin (1 ,&id); if (stmt.execute () != 0 ) { printf ("stmt.execute() failed.\n%s\n%s\n" ,stmt.m_sql,stmt.m_cda.message); return -1 ; } printf ("exec PL/SQL ok.\n" ); conn.commit (); }
运行效果
9、CLOB和BLOB字段的操作
sqlstatement类还可以操作CLOB和BLOB字段,在实际开发中,这种需求不多,本文就不演示了,如果您在项目开发中有这方面的需求,可以参考demo程序,示例程序位于freecplus/db/oracle目录中,如下:
filetoclob.cpp:把文本文件存入数据表的CLOB字段。
clobtofile.cpp:把数据表CLOB字段中的内容导出到文本文件中。
filetoblob.cpp:把文本文件存入数据表的BLOB字段。
blobtofile.cpp:把数据表BLOB字段中的内容导出到文本文件中。
八、应用经验
freecplus框架的connection和sqlstatement类把OCI的强大功能充分的发挥了出来,且性能卓越。本文提供的示例程序看上去简单,实则很精妙,希望大家多多思考,慢慢体会。
为了让大家完全掌握connection和sqlstatement类的用法,我将录制freecplus框架的专题视频,请大家多关注C语言技术网(www.freecplus.net )发布的内容。
七、版权声明
C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
来源:C语言技术网(www.freecplus.net )
作者:码农有道