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;
}


       唉,看完源代码,其实好多地方我也还是不明白,还请知道了的告诉我一下,谢谢了。

      

 

posted on 2011-09-28 17:14  好好单调  阅读(341)  评论(0编辑  收藏  举报