VC2005 + SQLite 3.6.3 编译、测试开发手记

偶然的机会对 SQLite 有了兴趣,花了半天的时间小小研究了一下,包括 VC2005 环境下 SQLite 的编译,开发测试等。

初次接触,只是测试了基本的数据库操作功能,更多的高级功能有待以后继续深入研究,废话少说,言归正传。

现在 SQLite 的最新版本是 V3.6.3 ,发布于 2008 9 22 ,详见 http://sqlite.org/ 的介绍。

还是补充一句什么是 SQLite 吧,“ SQLite 是一款轻型的数据库,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百 K 的内存就够了。它能够支持 Windows/Linux/Unix 等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl PHP Java 等,还有 ODBC 接口,同样比起 Mysql PostgreSQL 这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。”

简单的说, SQLite 的特点就是小巧、高效, SQLite 数据库只有一个文件,也可以说是文件数据库吧,对于某些桌面应用以及嵌入式应用来说, SQLite 可以提供相当高效的数据存储方案。如果你正在位自己的应用程序寻找一种数据管理方案的话,不妨考虑一下 SQLite

接着说 SQLite 如何在 VC 环境下进行开发。

SQLite 官网上当下来的,可以有 SQLite 命令行程序,还可以有运行支持的 DLL ,当然开源的 SQLite 还提供了完整的源码。

嵌入 SQLite 开发的程序发布时,需要提供 SQLite Dll 就行了,但是对于开发者来说,最方便的还是用 Lib 辅助开发,因此我们自己来编译 SQLite 就很有必要了(当然,也可以通过 DLL 直接获取 Lib ,但自己编译出来的感觉不一样,哈哈:) )。

好了,首先从 http://sqlite.org/download.html 上把最新的源码下载下来,注意, Source Code 有好几个版本,没搞太清楚各个版本都是干啥的,这里我们下载下来 sqlite-source-3_6_3.zip Zip 格式的,不是 gz 的,呵呵),当然把 sqlite-amalgamation-3.6.3.tar.gz 下载下来也是最好的,因为我们后面可能需要其中的一个文件( sqlite3.def ),不想下的话,从别的地方找一下就 Ok 了。

有了源码以后,我们先建立一个 Win32 的空白 DLL 项目,比如这里项目为 SQLiteLib ,然后把刚才下载的 SQLite 源码解压到一个文件夹(如 sqlite-source ),把这个文件夹复制到项目文件夹里,并加入到新建的工程中。

这样就完成了第一步,但是这个时侯如果你编译的话,会发现有好几个错误和 N 个警告。首先在项目解决方案里移除以下几个文件 tclsqlite.c shell.c rtree.c fts3.c fts3_hash.c fts3_icu.c fts3_porter.c fts3_tokenizer1.c fts3_tokenizer.c

其中 tclsqlite.c 用于生成基于 TCL API ,如果要编译,这需要另外下载 tcl.h shell.c 用于生成命令行模式的 sqlite.exe rTree.c 是建立数据库 R 树索引的模块, fts3*.c 是全文索引模块,这两个扩展模块直接编译的时候会提示以下错误,

1>fts3.obj : error LNK2005: _sqlite3_extension_init 已经在 rtree.obj 中定义

1>fts3.obj : error LNK2005: _sqlite3_api 已经在 rtree.obj 中定义

1>fts3_tokenizer.obj : error LNK2005: _sqlite3_api 已经在 rtree.obj 中定义

至于原因,一时半会儿也没找出来,就先不管它了,从项目中移除上面几个文件再编译就 Ok 了(移除 Rtree.c 是因为发现用其编译出来的库时会出错)。

(呵呵,初次测试的目的是基本应用,所以具体错误的原因就没深究,有兴趣的可以共同探讨一下,主要是 Rtree 和全文检索模块的应用)

接下里,我们在工程属性里,把“ N ”个警告忽略掉,配置属性 à C/C++-> 高级 à 禁用特定警告里,设置“ 4267;4244;4018;4996; ”。

然后再编译世界就清净了,呵呵,顺利编译出的有 DLL Lib 文件,接下里我们对 SQLite 进行简单的功能测试,体验一下 SQLite 编程的便利。

/************************************************/

建立一个新的测试工程,这里我们选择 MFC 应用程序( Dialog Based ),例如项目 SQLiteDEmo

在项目文件夹下建立一个 Lib 文件夹,把刚才生成的 Lib 文件和 Sqlite3.h 复制到该文件夹下,为了方便可以把 SQLiteLib SQLiteDemo 在一个解决方案里管理,设置共同的输出路径,并在生成时间里自动拷贝库文件,这样不用每次都手动来操作,还能保证用到的都是最新的编译版本。

SQLiteDemo 项目属性里,配置属性 à 链接器 à 输入 à 附加依赖性,设置为“ $(SolutionDir)lib/SQLite3.lib ”,这样就把 SQLite 库引用到了我们的工程中。

然后,在用到 SQLite 的文件里包含头文件 #include "../lib/sqlite3.h"

/************************************************/

接下来,我们进行简单的 SQLite 应用。

//连接数据库

void CSQLiteDemoDlg::OnBnClickedButtonConnect()

{

UpdateData();

m_strDB.Trim(_T(" /t/n"));;

if( m_strDB.IsEmpty() )

{

//AfxMessageBox(_T("请检查数据库参数!"));

m_strResult += _T("请检查数据库参数!/r/n");

return;

}

//

int result = 0;

//

LPSTR szTmp = new char[MAX_PATH];

wsprintfA(szTmp, "%ls", m_strDB);

result = sqlite3_open( szTmp, &m_db );//关键代码, 连接数据库

if( result )

{

//AfxMessageBox(_T("连接数据库失败!"));

m_strResult += m_strDB;

m_strResult += _T("/r/n");

m_strResult += _T("连接数据库失败!/r/n");

sqlite3_close(m_db);

}

else

{

m_strResult += m_strDB;

m_strResult += _T("/r/n");

SqliteQuery(_T("select name, sql from sqlite_master"));

//AfxMessageBox(_T("连接数据库成功!"));

m_strResult += _T("连接数据库成功!/r/n");

}

//

delete[] szTmp;

}

 

//执行语句

void CSQLiteDemoDlg::SqliteExec(CString strSQL)

{

strSQL.Trim(_T(" /t/n"));

if( strSQL.IsEmpty() )

{

//AfxMessageBox(_T("请检查参数!"));

m_strResult += _T("请检查执行语句!/r/n");

UpdateData(FALSE);

return;

}

//

int result = 0;

//

LPSTR szTmp = new char[MAX_PATH];

wsprintfA(szTmp, "%ls", strSQL);

 

LPSTR szMsg = NULL;

 

result = sqlite3_exec( m_db, szTmp, 0, 0, &szMsg);

 

if( result!=SQLITE_OK )

{

//AfxMessageBox(CString(szMsg));

m_strResult += CString(szMsg);

m_strResult += _T("/r/n");

}

 

delete[] szTmp;

}

 

//查询

void CSQLiteDemoDlg::SqliteQuery(CString strQuery)

{

m_strResult += _T("-----------------------------------/r/n");

double dbStartTime = clock();

//

char **ppTb = NULL;

int nRow, nCol;

nRow = nCol = 0;

//

strQuery.Trim(_T(" /t/n"));;

if( strQuery.IsEmpty() )

{

//AfxMessageBox(_T("请检查查询参数!"));

m_strResult += _T("请检查查询参数!/r/n");

return;

}

m_strResult += strQuery;

m_strResult += _T("/r/n");

int result = 0;

//

LPSTR szTmp = new char[MAX_PATH];

wsprintfA(szTmp, "%ls", strQuery);

LPSTR szMsg = NULL;

result = sqlite3_get_table( m_db, szTmp, &ppTb, &nRow, &nCol, &szMsg );

if( result!=SQLITE_OK )

AfxMessageBox(CString(szMsg));

else

{

CString strRes;

for( int i=0;i<=nRow;i++ )

{

strRes = _T("");

for( int j=0;j<nCol;j++ )

{

if( j>0 )

strRes += _T("/t|    ");

strRes += *(ppTb + i*nCol + j);

}

strRes += "/r/n";

m_strResult += strRes;

}

}

m_strResult += _T("-----------------------------------/r/n");

double dbEndTime = clock();

CString strTime;

strTime.Format(_T("查询花费时间: %.2f毫秒"), (double)(dbEndTime-dbStartTime));

m_strResult += strTime;

m_strResult += _T("/r/n");

//

sqlite3_free_table(ppTb);

delete[] szTmp;

UpdateData(FALSE);

}

///

以上是简单的功能测试,测试工程点击这里SQLiteDemo.zip 这里 下载。

欢迎大家就SQLite进行交流,好东西大家分享~~

©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页