• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • SQLite學習筆記(十)-- 事務基本概念和代碼實現(C++實現)

    標簽: SQLite  C++  代碼實例  事務

    1.事務基本概念

    • 什么是事務?
      事務是用戶定義的一些列數據操作,這些操作是一個完整的不可分的工作單元。一個事務要么全部執行,要么全部不執行。
    • 視圖案例
      例如銀行的轉賬操作,張三向李四轉賬1000元。該事務包含以下兩個操作:
      1.張三賬戶上扣除1000元;
      2.李四賬戶上增加1000元。
      這兩個操作就構成一個事務操作。兩個操作要么全部執行,要么全部不執行。只執行任意一個,都會導致賬戶金額的混亂。
      該事務的具體代碼見下文。
    • SQLite事務執行流程
      1.以begin語句開啟一個事務;
      2.依次執行事務中的所有操作,并檢查其是否執行成功;
      3.如果所有操作全部成功,則執行commit語句;否則執行rollback語句。

    2.代碼實例

    • 代碼說明
      本例主要展示用事務模式來執行轉賬操作。
    • 測試平臺
      1.開發語言:C++
      2.開發工具:VS2015
      3.操作系統:Win7 X64
    • 測試數據說明
      測試表為Account表,其結構如下:
      這里寫圖片描述
      測試表的內容如下:
      這里寫圖片描述

    • 具體代碼

    #include <iostream>
    #include <Windows.h>
    using namespace std;
    
    //sqlite3頭文件
    #include "sqlite3.h"
    //sqlite3庫文件
    #pragma comment(lib,"sqlite3.lib")
    
    //函數功能:將utf8字符轉gb2312字符
    //參數:    const char* utf8[IN]                   -- UTF8字符
    //返回值:  char*                                  -- gb2312字符
    char* U2G(const char* utf8)
    {
        int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
        wchar_t* wstr = new wchar_t[len + 1];
        memset(wstr, 0, len + 1);
        MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
        len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
        char* str = new char[len + 1];
        memset(str, 0, len + 1);
        WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
        if (wstr) delete[] wstr;
        return str;
    }
    
    //unicode字符轉utf8
    //函數功能:將gb2312字符轉換為utf8字符
    //參數:    const char* gb2312[IN]                   -- gb2312字符
    //返回值:  char*                                    -- UTF8字符
    char* G2U(const char* gb2312)
    {
        int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
        wchar_t* wstr = new wchar_t[len + 1];
        memset(wstr, 0, len + 1);
        MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
        len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
        char* str = new char[len + 1];
        memset(str, 0, len + 1);
        WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
        if (wstr) delete[] wstr;
        return str;
    }
    
    //函數功能:事務操作函數
    //參數:    sqlite3 *db[IN]                         --數據庫操作句柄
    //返回值:  bool                                    --函數執行成功,則返回true;否則返回false  
    bool BeginTranction(sqlite3 *db)
    {
        int iAmount = 1000;                 //假設轉賬金額為1000
        bool bRet = false;
        int rc;
        char sql[3000];
        char *pErrMsg = 0;
    
        //開啟事務
        rc = sqlite3_exec(db, "begin;", NULL, 0, &pErrMsg);
        if (rc != SQLITE_OK)
        {
            cout << "操作發生失敗,失敗原因:" << pErrMsg << endl;;
            sqlite3_free(pErrMsg);
            bRet = false;   
        }
        else
        {
            cout << "數據庫事務開啟成功" << endl;
    
            bool successFlag = false;
    
            //進行轉賬操作
            sprintf_s(sql, "UPDATE Account Set BALANCE=BALANCE-%d WHERE NAME='%s';", iAmount, G2U("張三"));
            rc = sqlite3_exec(db, sql, NULL, 0, &pErrMsg);
            if (rc != SQLITE_OK)
            {
                cout << "轉賬操作發生失敗,失敗原因:" << pErrMsg << endl;;
                sqlite3_free(pErrMsg);
                bRet = false;
            }
            else
            {
                cout << "張三轉出" << iAmount << "操作成功" << endl;
    
                sprintf_s(sql, "UPDATE Account Set BALANCE = BALANCE + %d WHERE NAME = '%s'; ", iAmount, G2U("李四"));
                rc = sqlite3_exec(db, sql, NULL, 0, &pErrMsg);
                if (rc != SQLITE_OK)
                {
                    cout << "轉賬操作發生失敗,失敗原因:" << pErrMsg << endl;;
                    sqlite3_free(pErrMsg);
                    bRet = false;
                }
                else
                {
                    cout << "李四收入" << iAmount << "操作成功" << endl;
                }
    
                successFlag = true;
            }
    
            if (successFlag)
            {
                //操作全部成功情況下,提交事務
                sqlite3_exec(db, "commit;", NULL, 0, 0);
                cout << "數據庫完成事務操作" << endl;
    
                bRet = false;
            }
            else
            {
                //操作沒有全部成功,需要回滾
                sqlite3_exec(db, "rollback;", NULL, 0, 0);
                cout << "事務操作失敗,回滾" << endl;
    
                bRet = true;
            }   
        }
    
        return bRet;
    }
    
    //函數功能:使用查詢表方式查詢賬戶數據
    //參數:    sqlite3 *db[IN]                         --數據庫操作句柄
    //返回值:  bool                                    --函數執行成功,則返回true;否則返回false  
    bool Select_QueryTable(sqlite3 *db)
    {
        bool bRet = false;
    
        int rc;
        char sql[3000];
        char *pErrMsg = 0;
        sprintf_s(sql, "SELECT * FROM 'Account';");
    
        string m_SqlCommand(sql);
        char** pResult;
        int nRow;
        int nCol;
        int nResult = sqlite3_get_table(db,
            m_SqlCommand.c_str(),
            &pResult, &nRow, &nCol, &pErrMsg);
        if (nResult != SQLITE_OK)
        {
            //注意,執行失敗,需要清理錯誤碼的內存空間
            sqlite3_free(pErrMsg);
            return false;
        }
    
        int nIndex = nCol;
        int cnt = 0;
        for (int i = 0; i<nRow; i++)
        {       
            for (int j = 0; j<nCol; j++)
            {
                cout << U2G(pResult[j]) << ":" << U2G(pResult[nIndex]) << "  ";
                ++nIndex;
            }
            cout << endl;
        }
        sqlite3_free_table(pResult);
    
        return true;
    }
    
    int main()
    {
        sqlite3 *pDataBase = NULL;                           
    
        //打開數據庫
        //如果路徑不含中文,可以不用轉碼。不過保險起見,建議全部轉碼。
        int iRet = sqlite3_open(G2U("E:\\sqlite數據庫\\testSQLite.db"), &pDataBase);
        if (iRet)
        {
            cout << "數據庫打開失敗,失敗原因:" << sqlite3_errmsg(pDataBase) << endl;   
        }
        else
        {
            cout << "數據庫打開成功!" << endl;
    
            cout << "原始數據:" << endl;
            //以查詢表方式查詢數據
            Select_QueryTable(pDataBase);
    
            //執行事務,張三轉賬給李四1000元
            BeginTranction(pDataBase);
    
            //轉賬結果
            cout << endl << "轉賬后數據數據:" << endl;
            Select_QueryTable(pDataBase);
    
            //關閉數據庫
            iRet= sqlite3_close(pDataBase);
            if (0 == iRet)
            {
                cout << "數據庫關閉成功!" << endl;
            }
        }
        getchar();
        return 0;
    }
    • 輸出結果
      這里寫圖片描述

    欄目導航
    上一篇:SQLite學習筆記(九)– 視圖的定義與刪除(C++實現)
    下一篇:無

    版權聲明:本文為u014337397原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/u014337397/article/details/80638183

    智能推薦

    ORACLE學習筆記-ORACLE基本概念

    ORACLE學習筆記-ORACLE基本概念 數據庫名 數據庫名是存儲在控制文件中的名稱,它代表的是數據庫,也就是數據庫包含的所有的物理文件的總稱。數據庫名即下圖的全局數據庫名,實例名即下圖的SID 查詢數據庫名稱SQL: 查詢數據庫當前實例名: **實例名 ** 用于響應某個數據庫操作的數據庫管理系統的名稱。實例名是由初始化參數文件的參數instance_name決定的。如果這個參數不被指定(即i...

    Java 學習筆記——基本概念

    Java 學習筆記——基本概念 類與對象 primitive 主要數據類型與引用 方法操作實例變量 萬物皆對象,真正的java程序只會讓對象與對象交互,交互即相互調用方法 類與對象 類是對象的藍圖,它會告訴虛擬機如何創建某種類型的對象。根據某類創建出來的額對象都會有自己的實例變量。 main()函數:在對象之外,用來(1)測試真正的類;(2)啟動你的java應用程序 pri...

    ElasticSearch學習筆記【一】基本概念

    基本概念 cluster:代表一個集群,集群中有多個節點,其中有一個為主節點,這個主節點是可以通過選舉產生的,主從節點是對于集群內部來說的。es的一個概念就是去中心化,字面上理解就是無中心節點,這是對于集群外部來說的,因為從外部來看es集群,在邏輯上是個整體,你與任何一個節點的通信和與整個es集群通信是等價的。 shards:代表索引分片,es可以把一個完整的索引分成多個分片,這樣的好處是可以把一...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    猜你喜歡

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    精品国产乱码久久久久久蜜桃不卡