Sqlite3 C/C++ 初级入门
以前只用过sql server 和 access,都是很简单的应用,利用ado连接上数据库,然后查询等。最近因为实际需要,被推荐使用sqlite3,当时第一次听到这个名词。然后百度了下,最后找到了官网http://www.sqlite.org/index.html,sqlite3是干什么的,我就不多说了,本身我自己也说不出个所以然,还不如直接看百度。
看了下官网上的介绍,然后就是Document下提供的简单入门文档,绕了半天弯路,最后才理解,sqlite3就是两个文件,sqlite3.h 和sqlite3.cpp。官网上的源代码文件几乎全下下来看了一下,找到了一个dll,但是没找到lib,所以花了大把时间去找或者自己生成这个lib,最终发现,在不更改这两这文件的前提下,没法生成lib(可能能生成,但是我目前是这么觉得)。
好了,废话不多说了,在找到了两个源文件之后,就能使用sqlite3了。建议在使用前看下http://www.sqlite.org/cintro.html这个文档,剩下的就只要从tp://www.sqlite.org/c3ref/funclist.html中找对应函数的说明吧。(强调一下,标题有说是初级入门,所以我自己也有很多不明白的地方,但是基本能够使用一些常用的数据库操作了)。其实最好的方式还是看官方的文档说明,不明白的地方自己去尝试,这样子才能明白具体是什么含义。这里推荐两个个管理器方便查看数据库管理文件,我最喜欢的是navicat lite,因为它是中文的,而且和sql server的管理器很像。另外也有sqlite database browser,这个不用安装就能用,但是和名字一样,就像一个浏览器,只适合浏览,操作上我不喜欢。
接下来就准备上代码了,从代码就能看出来,我是菜鸟,呵呵。代码里实现的功能就是创建(或者是打开)一个数据库,如果表不存在则添加一个表,在往表里面添加两条记录,然后取出。我目前只需要会这些,就只做了这些测试。
#include "stdafx.h" #include <iostream> #include <conio.h> #include "sqlite3.h" // 记得把sqlite3.h 和 sqlite3.cpp加入到工程中来 using namespace std; int main() { sqlite3* lpdDb = NULL; // 连接数据库用的一个对象 sqlite3_stmt* lpdExcute = NULL; // 这个对象怎么称呼。。 我也不知道,好像有叫它为事务的,我看了下statement的意思,有指令的意思,就当作是指令(sql就是指令,哈哈)句柄了吧 do { // 建立或者打开数据库 int liRet = sqlite3_open_v2( "sqltest.db",//NULL, // 这里指名数据库的名称和存放路径, 如果为空,在磁盘中临时建立一个数据库,当关闭后会自动删除 &lpdDb, // sqlite3对象指针,后面就全靠这个指针与数据库挂钩了 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, // 指名打开或者创建这个数据库的一些标记 NULL // 这个参数文档里说的蛮麻烦的,我没看懂。。。。。。 不过暂时也不需要用。。 ); if( SQLITE_OK != liRet ) break; // 判断表是否存在,不存在则创建它 // sql学的很简单,搜了下百度,看不懂那些判断表是否存在的sql语句,所以就用种方式了。。。唉 char lscIsExit[] = "select * from stocks"; // 这个sqlite函数相当于是sql查询工具中的检查器,能够检测sql语句的正确性 liRet = sqlite3_prepare_v2( lpdDb, // 数据库连接指针 lscIsExit, // utf-8编码的sql语句 sizeof(lscIsExit), // sql语句的最大长度,字节数 &lpdExcute, // 指令句柄 NULL // 最后一个参数是当sql语句没执行完时,能返回的一个指针指向没执行完的部分,基本不用。sql语句没执行完,。。。还能做什么? ); if(SQLITE_ERROR == liRet) // sql语句错误或者不存在,创建表 { // 创建新的数据表 char lscSqlCreate[] = "create table stocks( \ stockname TEXT not null primary key, \ stockcode TEXT not null, \ exchange TEXT not null, \ pyname TEXT not null \ )"; liRet = sqlite3_prepare_v2(lpdDb,lscSqlCreate,sizeof(lscSqlCreate),&lpdExcute,NULL); if(SQLITE_ERROR == liRet) break; // 执行sql语句 liRet = sqlite3_step(lpdExcute); if(SQLITE_DONE != liRet) // 执行的是没有返回结果集的sql语句时,返回值是SQLITE_DONE break; sqlite3_finalize(lpdExcute); // 这个sql语句的利用结束了,就调用这个函数 // 插入新的数据 // 这里sql语句里面使用通配符,在后面只需要绑定对应的值就能直接执行sql语句,而不用多次调用sqlite3_prepare_v2函数了 // 当然也可以不用通配符,在这里特地使用通配符,练习一下,嘿嘿。 char lscInsertValue[] ="insert into stocks(stockname,stockcode,exchange,pyname) values(?,?,?,?)"; if(SQLITE_OK != sqlite3_prepare_v2(lpdDb,lscInsertValue,-1,&lpdExcute,NULL)) break; // 绑定参数 // 注意当存入汉字的时候,应该使用这个函数,而不是sqlite3_bind_text(使用这个函数会失败,即使指定的空间大小是足够的,不知道为什么) // 区别就在于第三个参数和第四个参数。 liRet = sqlite3_bind_text16( lpdExcute, 1, // 参数的索引值,最左边的为1 L"大智慧", // 参数值 -1,//sizeof(L"大智慧"), // 参数的字节数,如果参数为负数,则遇到第一个结束符时终止 SQLITE_STATIC // 这个参数当该函数返回失败结果时,对参数值的释放 ); if(SQLITE_OK != liRet)break; if(SQLITE_OK != sqlite3_bind_text(lpdExcute,2,"601519",-1,SQLITE_STATIC))break; if(SQLITE_OK != sqlite3_bind_text(lpdExcute,3,"sh",-1,SQLITE_STATIC))break; if(SQLITE_OK != sqlite3_bind_text(lpdExcute,4,"dzh",-1,SQLITE_STATIC))break; // 执行sql语句,插入记录 if(SQLITE_DONE != sqlite3_step(lpdExcute))break; // 之前以为这个函数能将有绑定上的数据清理掉,然后再直接重新绑定就行了,但是发现还是要调用下面那个函数。并且不要这个函数也可以 //liRet = sqlite3_clear_bindings(lpdExcute); // 这个函数就是使得lpdExcute恢复到刚调用完sqlite3_prepare_v2的状态 liRet = sqlite3_reset(lpdExcute); // 继续插入一条记录 if(SQLITE_OK != sqlite3_bind_text16(lpdExcute,1,L"海马汽车",-1,SQLITE_STATIC))break; if(SQLITE_OK != sqlite3_bind_text(lpdExcute,2,"000572",-1,SQLITE_STATIC))break; if(SQLITE_OK != sqlite3_bind_text(lpdExcute,3,"sz",-1,SQLITE_STATIC))break; if(SQLITE_OK != sqlite3_bind_text(lpdExcute,4,"hmqc",-1,SQLITE_STATIC))break; if(SQLITE_DONE != sqlite3_step(lpdExcute))break; sqlite3_finalize(lpdExcute); } // 查询数据 // 这里顺便试了下sqlite3支持的字符串连接方式是oracle的方式,网上搜的。 char lscSqlSelect[] = "select stockname,exchange||''||stockcode from stocks"; if(SQLITE_OK != sqlite3_prepare_v2(lpdDb,lscSqlSelect,-1,&lpdExcute,NULL)) break; if(SQLITE_ROW != sqlite3_step(lpdExcute)) break; int liCountColums = sqlite3_column_count(lpdExcute); if(2 != liCountColums) { cout<<"查询结果集的列数不对"<<endl; break; } // 获取列值 int i = 0; setlocale(LC_ALL, "chs"); // 使得控制台支持unicode汉字显示 do { // 注意第一列是存入unicode,所以用16版本的函数 int liCbStockName = sqlite3_column_bytes16( lpdExcute, 0 ); if(0 == liCbStockName)break; wchar_t* lswStockName = (wchar_t*)sqlite3_column_text16(lpdExcute,0); const unsigned char* lscColumValue= sqlite3_column_text( lpdExcute, 1 // 列索引 ); cout << "CbStockName:"<<liCbStockName<<endl; wcout << lswStockName << " "; cout << lscColumValue << endl; }while(SQLITE_DONE != sqlite3_step(lpdExcute)); cout<<endl; liRet = sqlite3_finalize(lpdExcute); if(SQLITE_OK != liRet) { cout<< "sqlite3_finalize之前存在错误,错误代码为:"<<liRet <<endl; } // 关闭连接 while(SQLITE_BUSY == sqlite3_close(lpdDb)) { cout<< "不能关闭数据库连接,数据库正在使用中。。。"<<endl; cout<< "按人任意键再次尝试关闭数据库连接"<<endl; _getch(); } cout<<"数据库成功关闭。"<<endl; _getch(); return 0; }while(false); cout<<"出错了,错误代码:"<<sqlite3_errcode(lpdDb)<<" 错误描述:"<<sqlite3_errmsg(lpdDb)<<endl; if(NULL != lpdExcute) { int liRet = sqlite3_finalize(lpdExcute); if(SQLITE_OK != liRet) { cout<< "sqlite3_finalize之前存在错误,错误代码为:"<<liRet <<endl; } } while(SQLITE_BUSY == sqlite3_close(lpdDb)) { cout<< "不能关闭数据库连接,数据库正在使用中。。。"<<endl; cout<< "按人任意键再次尝试关闭数据库连接"<<endl; _getch(); } cout<<"数据库成功关闭。"<<endl; _getch(); return 1; }
唉,看完源代码,其实好多地方我也还是不明白,还请知道了的告诉我一下,谢谢了。