windows下sqlite的使用

下载:

下载地址:http://www.sqlite.org/download.html

在windows平台进行开发,需要下载以下文件(版本可能不同):
sqlite-dll-win64-x64-3330000.zip
sqlite-tools-win32-x86-3330000.zip
sqlite-amalgamation-3330000.zip

准备头文件和库文件:

创建sqlite3目录,在sqlite3下创建include子目录,用于收集头文件,在sqlite3下创建lib子目录,用于收集库文件。

解压sqlite-amalgamation-3330000.zip,得到源码,拷贝其中的*.h文件到sqlite3\include。
解压sqlite-dll-win64-x64-3330000.zip,得到sqlite3.dll和sqlite3.def文件,拷贝它们到sqlite3\lib。

由于缺少sqlite3.lib文件,VS应用程序将无法链接sqlite库,可用以下的方法生成:

首先,必须确保系统已经安装VS开发工具,然后在操作系统查找栏那里搜索”命令提示”,找到对应的控制台工具,如”Visual Studio 2008 命令提示“,点击进入命令输入状态。
然后,在命令提示符下,输入cd命令切换到sqlite3\lib目录,并执行命令:lib /DEF:sqlite3.def /MACHINE:X64,这时会提示生成sqlite3.lib和sqlite3.exp文件,可以在sqlite3\lib目录下进行确认。

了解命令工具用法:

解压sqlite-tools-win32-x86-3330000.zip,得到3个可执行文件,双击运行其中的sqlite3.exe,进入命令提示符,下面举例几个简单的用法。

创建或打开数据库:
.open test.db

查看当前库存在的数据表:
.tables

创建表:
CREATE TABLE "tbtest" (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name VARCHAR(32) NOT NULL
);

插入记录:
insert into tbtest(id,name) values(null, "aaa");

查询记录:
select * from tbtest;

可以看到有两种语法风格,以.开头的表示sqlite3命令语法 和 以;结尾的SQL命令语法。具体这里不再过多说明,请读者去百度搜索更详细和权威的资料。

了解程序API用法:

主要是连接、断开、查询(SELECT)、执行(INSERT、UPDATE),先分开来看。

连接:
sqlite3 *pDB = NULL;
int rc = sqlite3_open("./test.db", &pDB);
if (rc != 0)
    return false;

断开:
if (pDB)
{
    sqlite3_close(pDB);
    pDB = NULL;
}

查询:
char *pErrMsg = NULL;
int rc = sqlite3_exec(pDB, “select * from tbtest”, callBack4selectSQL, NULL, &pErrMsg);
if (rc != 0)
{
    sqlite3_free(pErrMsg);
}

因为查询的结果是以回调的方式给出的,留意sqlite3_exec的第3、4个参数,分别表示回调的函数名和上下文传参,我这里定义一个简单的回调函数,暂时没有使用上下文,sqlite3_exec内部每查到一行回调一次:

int callBack4selectSQL(void* pParam, int argc, char ** argv, char ** szColName)
{
    for (int i = 0; i < argc; ++i)
    {
        if (argv[i] != NULL)
        {
            printf("%s : %s \n", szColName[i], argv[i]);
        }
    }
    return 0;
}

执行:
char *pErrMsg = NULL;
int rc = sqlite3_exec(pDB, “insert into tbtest(id,name) values(null,\”aaa\”);”, NULL, NULL, &pErrMsg);
if (rc != 0)
{
    sqlite3_free(pErrMsg);
}

封装类:

在实际的软件工程中,考虑到代码的复用和可维护性,还是需要对sqlite进行适当的封装的。这里,我贴出一个,方便大家复用。在这个例子中,有实现初使化时自动检测数据表是否存在,不存在则创建的逻辑,这里需要大家根据自己的情况做适当修改。

头文件,请保存文件名为sqlitewrap.h

#pragma once

#include <string>
#include <vector>
#include <sqlite3.h>

// SQLite操作封装
class CSQLiteWrap
{
public:

    // 单例
    static CSQLiteWrap* getInstance();

    explicit CSQLiteWrap(const std::string& strDB);
    virtual ~CSQLiteWrap();

    // 执行SQL
    int excuteSQL(const std::string& strSQL, std::string& strErrMsg);

    // 查询SQL
    typedef std::pair<std::string, std::string> FIELD_t;
    typedef std::vector<FIELD_t> ROW_t;
    typedef std::vector<ROW_t> ROWS_t;
    int selectSQL(const std::string& strSQL, ROWS_t& rows, std::string& strErrMsg);

private:

    // 连接数据库
    bool __connectDB();

    // 关闭数据库
    void __disConnectDB();

    // 初使化表格
    bool __initTables();

    // 检查表格是否存在
    bool __checkTable(const std::string& strTable, bool &isExist);

    // 创建表格
    bool __createTable(const std::string& strSQL);

    // 查询SQL的回调
    static int __callBack4selectSQL(void* pParam, int argc, char ** argv, char ** szColName);

private:
    std::string m_strDB;
    bool m_bConnected;
    bool m_bInited;
    sqlite3 *m_pDB;
};

实现文件,请保存文件名为sqlitewrap.cpp

#include "sqlitewrap.h"

#include <windows.h>
#include "helper.h"

#define SQLITE_DBNAME "./test.db"

// 单例
CSQLiteWrap* CSQLiteWrap::getInstance()
{
    static CSQLiteWrap* g_pSQLiteWrap = NULL;

    if (g_pSQLiteWrap == NULL)
    {
        g_pSQLiteWrap = new CSQLiteWrap(SQLITE_DBNAME);
    }

    return g_pSQLiteWrap;
}

CSQLiteWrap::CSQLiteWrap(const std::string& strDB)
: m_strDB(strDB)
, m_bConnected(false)
, m_bInited(false)
, m_pDB(NULL)
{
    m_bConnected = __connectDB();
    m_bInited = __initTables();
}

CSQLiteWrap::~CSQLiteWrap()
{
    __disConnectDB();
}

// 执行SQL
int CSQLiteWrap::excuteSQL(const std::string& strSQL, std::string& strErrMsg)
{
    if (!m_bInited)
        return -1;

    char *pErrMsg = NULL;
    int rc = sqlite3_exec(m_pDB, strSQL.c_str(), NULL, NULL, &pErrMsg);
    if (rc != 0)
    {
        strErrMsg = pErrMsg;
        sqlite3_free(pErrMsg);
    }

    return rc;
}

// 查询SQL
int CSQLiteWrap::selectSQL(const std::string& strSQL, CSQLiteWrap::ROWS_t& rows, std::string& strErrMsg)
{
    if (!m_bInited)
        return -1;

    char *pErrMsg = NULL;
    int rc = sqlite3_exec(m_pDB, strSQL.c_str(), __callBack4selectSQL, (void*)&rows, &pErrMsg);
    if (rc != 0)
    {
        strErrMsg = pErrMsg;
        sqlite3_free(pErrMsg);
    }

    return rc;
}

// 连接数据库
bool CSQLiteWrap::__connectDB()
{
    int rc = sqlite3_open(m_strDB.c_str(), &m_pDB);
    if (rc != 0)
    {
        OutputDebugStringA(CFuncHelper::toString("@CSQLiteWrap::__connectDB Can't open database:[%s]", m_strDB.c_str()).c_str());
        return false;
    }

    return true;
}

// 关闭数据库
void CSQLiteWrap::__disConnectDB()
{
    if (m_bConnected && m_pDB)
    {
        sqlite3_close(m_pDB);
        m_pDB = NULL;
        m_bConnected = false;
    }
}

// 初使化表格
bool CSQLiteWrap::__initTables()
{
    if (!m_bConnected)
        return false;

    // 尝试创建用户表
    {
        bool bExist = false;
        bool bRet = __checkTable("tbUser", bExist);
        if (!bRet)
            return false;

        if (!bExist)
        {
            std::string strSQL = "CREATE TABLE \"tbUser\" ( \
                    userId INTEGER PRIMARY KEY AUTOINCREMENT, \
                    name VARCHAR(32) NOT NULL, \
                    sex INTEGER, \
                    birthday VARCHAR(32), \
                    address VARCHAR(128), \
                    tel VARCHAR(32), \
                    createTime VARCHAR(32), \
                    updateTime VARCHAR(32) \
                    );";

            bRet = __createTable(strSQL);
            if (!bRet)
                return false;
        }
    }

    // 尝试创建会话表
    {
        bool bExist = false;
        bool bRet = __checkTable("tbSession", bExist);
        if (!bRet)
            return false;

        if (!bExist)
        {
            std::string strSQL = "CREATE TABLE \"tbSession\" ( \
                    userId INTEGER NOT NULL, \
                    sessionId INTEGER NOT NULL, \
                    config TEXT NOT NULL, \
                    createTime VARCHAR(32), \
                    updateTime VARCHAR(32), \
                    PRIMARY KEY(userId, sessionId) \
                    );";

            bRet = __createTable(strSQL);
            if (!bRet)
                return false;
        }
    }

    return true;
}

// 检查表格是否存在
bool CSQLiteWrap::__checkTable(const std::string& strTable, bool &isExist)
{
    if (!m_bConnected)
        return false;

    std::string strSQL = "select * from sqlite_master where type = \"table\" and name = \"" + strTable + "\";";
    CSQLiteWrap::ROWS_t rows;
    char *pErrMsg = NULL;
    int rc = sqlite3_exec(m_pDB, strSQL.c_str(), __callBack4selectSQL, (void*)&rows, &pErrMsg);
    if (rc != 0)
    {
        OutputDebugStringA(CFuncHelper::toString("@CSQLiteWrap::__checkTable exec sql:[%s] err:[%s]", strSQL.c_str(), pErrMsg).c_str());
        sqlite3_free(pErrMsg);
        return false;
    }

    for (CSQLiteWrap::ROWS_t::iterator iterRow = rows.begin(); iterRow != rows.end(); ++iterRow)
    {
        for (CSQLiteWrap::ROW_t::iterator iterField = iterRow->begin(); iterField != iterRow->end(); ++iterField)
        {
            if (iterField->first == std::string("tbl_name") && iterField->second == strTable)
            {
                isExist = true;
                break;
            }
        }

        if (isExist)
            break;
    }

    OutputDebugStringA(CFuncHelper::toString("@CSQLiteWrap::__checkTable exec sql:[%s] ok, table isexist:[%d]", strSQL.c_str(), isExist).c_str());
    return true;
}

// 创建表格
bool CSQLiteWrap::__createTable(const std::string& strSQL)
{
    if (!m_bConnected)
        return false;

    char *pErrMsg = NULL;
    int rc = sqlite3_exec(m_pDB, strSQL.c_str(), NULL, NULL, &pErrMsg);
    if (rc != 0)
    {
        OutputDebugStringA(CFuncHelper::toString("@CSQLiteWrap::__createTable exec sql:[%s] err:[%s]", strSQL.c_str(), pErrMsg).c_str());
        sqlite3_free(pErrMsg);
        reurn false;
    }

    OutputDebugStringA(CFuncHelper::toString("@CSQLiteWrap::__createTable exec sql:[%s] ok", strSQL.c_str()).c_str());
    return true;
}

// 查询SQL的回调
int CSQLiteWrap::__callBack4selectSQL(void* pParam, int argc, char ** argv, char ** szColName)
{
    CSQLiteWrap::ROWS_t* pRows = (CSQLiteWrap::ROWS_t*)pParam;
    CSQLiteWrap::ROW_t row;

    for (int i = 0; i < argc; ++i)
    {
        if (argv[i] != NULL)
        {
        //OutputDebugStringA(CFuncHelper::toString("@CSQLiteWrap::__callBack4selectSQL %s : %s", szColName[i], argv[i]).c_str());
            row.push_back( std::make_pair(szColName[i], argv[i]) );
        }
    }

    pRows->push_back(row);
    return 0;
}

还有一个helper帮助类,头文件helper.h内容如下:

#pragma once

#include <stdarg.h>
#include <string>

class CFuncHelper
{
public:
    static std::string toString(const char* sFormat, ...);
};

实现文件helper.cpp内容如下:

#include "helper.h"

std::string CFuncHelper::toString(const char* sFormat, ...)
{
    char sLine[1024] = { 0 };

    va_list va;
    va_start(va, sFormat);
    vsnprintf(sLine, sizeof(sLine)-1, sFormat, va);
    va_end(va);

    return std::string(sLine);
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343