SQLite學習筆記(十)-- 事務基本概念和程式碼實現(C++實現)
阿新 • • 發佈:2019-02-11
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;
}
- 輸出結果