0
点赞
收藏
分享

微信扫一扫

SQLite事务并发访问问题?

郝春妮 2022-09-19 阅读 58


 

//描述:执行命令 
void ExecSqlCmd(sqlite3 *db, const char *sql, const char *pszThrdName)
{
int iRet;
char *err_msg = 0;
char buf[1024];

if ((iRet = sqlite3_exec(db, sql, NULL, 0, &err_msg)) != SQLITE_OK)
{
sqlite3_free(err_msg);
TRACE("%s error, sql=%s\n", pszThrdName, sql);
}
}

//描述:开始事务处理
int BeginTransaction(sqlite3 *db, const char *pszThrdName)
{
//return ExecSqlCmd(db, "BEGIN", pszThrdName);
return ExecSqlCmd(db, "BEGIN IMMEDIATE TRANSACTION", pszThrdName);
//ExecSqlCmd(db, "BEGIN EXCLUSIVE TRANSACTION", pszThrdName);
//ExecSqlCmd(db, "BEGIN TRANSACTION", pszThrdName);
}


//描述:结束事务处理
void CommitTransaction(sqlite3 *db, const char *pszThrdName)
{
ExecSqlCmd(db, "COMMIT", pszThrdName);
}


//描述:回滚事务处理
void RollBackTransaction(sqlite3 *db, const char *pszThrdName)
{
ExecSqlCmd(db, "ROLLBACK", pszThrdName);
}

typedef struct TThrdPara{
int idx;
const char *pszThrName;
};
sqlite3 *db = NULL;
void TestTransactionLock(int iThrd, const char *pszThreadName)
{
sqlite3_stmt *stmt;
int iRet, iLen;
char *pszSqliteName = USER_DATA_SQLITE3_PATH"gwooDb";
char *errmsg = NULL;
char **results;
static bool fInit = false;

if (!fInit)
{
fInit = true;
if ((iRet=sqlite3_open(pszSqliteName, &db)) > 0)
{
TRACE("can't open db!\n", sqlite3_errmsg(db));
sqlite3_close(db);
return;
}

char *sqlCreateTable = "CREATE TABLE TbReal (StartTime DATETIME,SuccTime DATETIME,SaveTime DATETIME,MtrAddr BLOB, x20000200 BLOB, x20010200 BLOB)";
iRet = sqlite3_exec(db, sqlCreateTable, 0, 0, &errmsg);
}

if (iThrd==1 || iThrd==2) //写数据
{
while (1)
{
BeginTransaction(db, pszThreadName);
char *insertSql = "INSERT INTO TbReal (StartTime, SuccTime, SaveTime, MtrAddr, x20000200) \
VALUES(DATETIME(1551262800, 'unixepoch'), DATETIME(1551263014, 'unixepoch'), DATETIME(1551262800, 'unixepoch'), \"000337448041\",?)";
if ((iRet=sqlite3_prepare(db, insertSql, -1, &stmt, NULL)) == SQLITE_OK)
{
char szBlob[] = {0x01, 0x03, 0x12, 0x01, 0x0a, 0x12, 0x00, 0x14, 0x12, 0x00, 0x1e };
sqlite3_bind_blob(stmt, 1, szBlob, sizeof(szBlob), SQLITE_TRANSIENT);
if ((iRet=sqlite3_step(stmt)) != SQLITE_DONE)
{
sqlite3_finalize(stmt);
CommitTransaction(db, pszThreadName);
TRACE("ThreadName: %s sqlite3_step error!\n", pszThreadName);
return;
}
TRACE("%s: ", pszThreadName);
for (int i=0; i<sizeof(szBlob); i++)
TRACE("%02x ", szBlob[i]);
TRACE("\n");
}

sqlite3_finalize(stmt);
CommitTransaction(db, pszThreadName);
Sleep(10);
}
}
else if (iThrd==3 || iThrd==4) //读数据
{
while (1)
{
char *queryFieldx20000200SameDate1 = "SELECT StartTime FROM TbReal WHERE MtrAddr==\"000337448041 \"";
if (sqlite3_prepare(db, queryFieldx20000200SameDate1, -1, &stmt, 0) == SQLITE_OK)
{
BYTE bRdBuf[128]={0};
if ((iRet=sqlite3_step(stmt)) == SQLITE_ROW)
{
if ((iLen=sqlite3_column_bytes(stmt, 0)) > 0)
memcpy(bRdBuf, sqlite3_column_blob(stmt, 0), iLen);
}
TRACE("%s: ", pszThreadName);
for (int i=0; i<iLen; i++)
TRACE("%02x ", bRdBuf[i]);
TRACE("\n");
}
sqlite3_finalize(stmt);
Sleep(10);
}
}
}



TThreadRet TrancsationThread(void* pvArg)
{
TThrdPara *pTrdPara = (TThrdPara*)pvArg;

TRACE("TrancsationThread: idx=%d, TrdName=%s\n", pTrdPara->idx, pTrdPara->pszThrName);

TestTransactionLock(pTrdPara->idx, pTrdPara->pszThrName);

return 1;
}

void MakeThreadTest()
{
TThrdPara tTrdPara1, tTrdPara2;

tTrdPara1.idx = 1;
tTrdPara1.pszThrName = "线程1";
NewThread(TrancsationThread, &tTrdPara1, 8192, THREAD_PRIORITY_NORMAL);

tTrdPara2.idx = 2;
tTrdPara2.pszThrName = "线程2";
NewThread(TrancsationThread, &tTrdPara2, 8192, THREAD_PRIORITY_NORMAL);
//NewThread(CheckNetThread, NULL, 8192, THREAD_PRIORITY_NORMAL);
tTrdPara2.idx = 3;
tTrdPara2.pszThrName = "线程3";
NewThread(TrancsationThread, &tTrdPara2, 8192, THREAD_PRIORITY_NORMAL);
//NewThread(CheckNetThread, NULL, 8192, THREAD_PRIORITY_NORMAL);
tTrdPara2.idx = 4;
tTrdPara2.pszThrName = "线程4";
NewThread(TrancsationThread, &tTrdPara2, 8192, THREAD_PRIORITY_NORMAL);
//NewThread(CheckNetThread, NULL, 8192, THREAD_PRIORITY_NORMAL);
while(1)
{
Sleep(1000);
}
}

int main()
{
MakeThreadTest();
}

 

未加锁时事务开始、提交出现报错,日志如下

TrancsationThread: idx=1, TrdName=线程1
TrancsationThread: idx=2, TrdName=线程2
线程2 error, iRet=21, sql=BEGIN IMMEDIATE TRANSACTION, err_msg=(null)
TrancsationThread: idx=3, TrdName=线程3
TrancsationThread: idx=4, TrdName=线程4
线程1: ok
线程4: ok
线程3: ok
线程2: ok
线程4: ok
线程1: ok
线程3: ok
线程3: ok
线程2: ok
线程4: ok
线程1: ok
线程4: ok
线程3: ok
线程4: ok
线程2: ok
线程1: ok
线程3: ok
线程4: ok
线程2: ok
线程3: ok
线程1: ok
线程4: ok
线程2: ok
线程3: ok
线程4: ok
线程3: ok
线程1: ok
线程2: ok
线程4: ok
线程3: ok
线程1: ok
线程4: ok
线程3: ok
线程4: ok
线程2: ok
线程1: ok
线程3: ok
线程4: ok
线程2: ok
线程4: ok
线程1: ok
线程3: ok
线程4: ok
线程3: ok
线程2: ok
线程4: ok
线程3: ok
线程1: ok
线程2: ok
线程4: ok
线程3: ok
线程3: ok
线程4: ok
线程1: ok
线程3: ok
线程2: ok
线程4: ok
线程3: ok
线程1: ok
线程4: ok
线程2: ok
线程3: ok
线程1: ok
线程4: ok
线程3: ok
线程2: ok
线程4: ok
线程3: ok
线程1: ok
线程4: ok
线程3: ok
线程2: ok
线程3: ok
线程4: ok
线程1: ok
线程4: ok
线程3: ok
线程2: ok
线程1: ok
线程4: ok
线程3: ok
线程2: ok
线程4: ok
线程3: ok
线程1: ok
线程2: ok
线程4: ok
线程3: ok
线程3: ok
线程1: ok
线程4: ok
线程3: ok
线程2: ok
线程1: ok
线程4: ok
线程3: ok
线程2: ok
线程3: ok
线程4: ok
线程1: ok
线程2: ok
线程4: ok
线程3: ok
线程3: ok
线程4: ok
线程1: ok
线程3: ok
线程4: ok
线程2: ok
线程1: ok
线程4: ok
线程3: ok
线程3: ok
线程4: ok
线程2: ok
线程3: ok
线程4: ok
线程1: ok
线程2: ok
线程3: ok
线程4: ok
线程1: ok
线程3: ok
线程4: ok
线程3: ok
线程2: ok
线程1: ok
线程4: ok
线程3: ok
线程2: ok
线程4: ok
线程1: ok
线程3: ok
线程4: ok
线程3: ok
线程4: ok
线程2: ok
线程4: ok
线程3: ok
线程1: ok
线程2: ok
线程4: ok
线程3: ok
线程1: ok
线程3: ok
线程2: ok
线程4: ok
线程1: ok
线程3: ok
线程2: ok
线程4: ok
线程3: ok
线程1: ok
线程4: ok
线程3: ok
线程2: ok
线程4: ok
线程1: ok
线程3: ok
线程3: ok
线程4: ok
线程2: ok
线程1: ok
线程3: ok
线程4: ok
线程3: ok
线程2: ok
线程1: ok
线程4: ok
线程3: ok
线程4: ok
线程2: ok
线程3: ok
线程4: ok
线程1: ok
线程2: ok
线程4: ok
线程3: ok
线程1: ok
线程4: ok
线程3: ok
线程4: ok
线程2: ok
线程1: ok
线程3: ok
线程4: ok
线程2: ok
线程1: ok
线程4: ok
线程2: ok
线程3: ok
线程1: ok
线程3: ok
线程4: ok

上面代码需增加实物开启的防错机制检测

      if (BeginTransaction(db, pszThreadName) != SQLITE_OK)
{
Sleep(10);
continue;
}

 

举报

相关推荐

0 条评论