SQLite事務與自增深度分析

来源:http://www.cnblogs.com/nnhy/archive/2017/01/27/SQLiteRowIDAndTransaction.html
-Advertisement-
Play Games

SQLite什麼都好,就怕“database is locked”這些年來想盡辦法去規避它。測試代碼: static void Test2() { XCode.Setting.Current.TransactionDebug = true; XTrace.WriteLine(Role.Meta.Co ...


SQLite什麼都好,就怕“database is locked”這些年來想盡辦法去規避它。

測試代碼:

static void Test2()
{
    XCode.Setting.Current.TransactionDebug = true;

    XTrace.WriteLine(Role.Meta.Count + "");
    XTrace.WriteLine(Log.Meta.Count + "");
    Console.Clear();

    Task.Run(() => TestTask(1));
    Thread.Sleep(1000);
    Task.Run(() => TestTask(2));
}

static void TestTask(Int32 tid)
{
    try
    {
        XTrace.WriteLine("TestTask {0} Start", tid);
        using (var tran = Role.Meta.CreateTrans())
        {
            var role = new Role();
            role.Name = "R" + DateTime.Now.Millisecond;
            role.Save();
            XTrace.WriteLine("role.ID={0}", role.ID);

            Thread.Sleep(3000);

            role = new Role();
            role.Name = "R" + DateTime.Now.Millisecond;
            role.Save();
            XTrace.WriteLine("role.ID={0}", role.ID);

            Thread.Sleep(3000);

            if (tid == 2) tran.Commit();
        }
    }
    catch (Exception ex)
    {
        XTrace.WriteException(ex);
    }
    finally
    {
        XTrace.WriteLine("TestTask {0} End", tid);
    }
}
View Code

 

預熱環境以後,我們開了兩個任務去執行測試函數,間隔1秒。
測試函數負責插入兩行數據,間隔3秒。
第一個任務最後會回滾,第二個任務提交。
顯然,兩個任務會重疊。

 

比較好奇,任務1申請得到自增1後,任務2申請得到的自增會是多少?
任務1回滾以後,它所申請得到的自增數字如何處理?


結果:

 

02:45:03.470  6 Y 5 TestTask 1 Start
02:45:03.470  6 Y 5 Transaction.Begin ReadCommitted
02:45:03.486  6 Y 5 Select Count(*) From Role Where Name='R470'
02:45:03.501  6 Y 5 Insert Into Role(Name, IsSystem, Permission) Values('R470', 0, '');Select last_insert_rowid() newid
02:45:03.517  6 Y 5 開始初始化實體類UserX
02:45:03.517  6 Y 5 完成初始化實體類UserX
02:45:03.533  6 Y 5 role.ID=11
02:45:04.486 14 Y 6 TestTask 2 Start
02:45:04.486 14 Y 6 Transaction.Begin ReadCommitted
02:45:04.486 14 Y 6 Select Count(*) From Role Where Name='R486'
02:45:04.486 14 Y 6 Insert Into Role(Name, IsSystem, Permission) Values('R486', 0, '');Select last_insert_rowid() newid
02:45:05.251 15 Y 7 Transaction.Begin ReadCommitted
02:45:05.251 15 Y 7 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 11, 0, '2017-01-27 02:45:03', 'ID=11,Name=R470');Select last_insert_rowid() newid
02:45:06.548  6 Y 5 Select Count(*) From Role Where Name='R548'
02:45:06.548  6 Y 5 Insert Into Role(Name, IsSystem, Permission) Values('R548', 0, '');Select last_insert_rowid() newid
02:45:06.548  6 Y 5 role.ID=12
02:45:09.555  6 Y 5 Transaction.Rollback ReadCommitted
02:45:09.555  6 Y 5 TestTask 1 End
02:45:09.618 14 Y 6 SQL耗時較長,建議優化 5,120毫秒 Insert Into Role(Name, IsSystem, Permission) Values('R486', 0, '');Select last_insert_rowid() newid
02:45:09.618 14 Y 6 role.ID=11
02:45:12.633 14 Y 6 Select Count(*) From Role Where Name='R633'
02:45:12.633 14 Y 6 Insert Into Role(Name, IsSystem, Permission) Values('R633', 0, '');Select last_insert_rowid() newid
02:45:12.633 14 Y 6 role.ID=12
02:45:15.649 14 Y 6 Transaction.Commit ReadCommitted
02:45:15.649 14 Y 6 TestTask 2 End
02:45:15.774 15 Y 7 SQL耗時較長,建議優化 10,519毫秒 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 11, 0, '2017-01-27 02:45:03', 'ID=11,Name=R470');Select last_insert_rowid() newid
02:45:15.774 15 Y 7 Transaction.Commit ReadCommitted
02:45:16.622 16 Y 9 Transaction.Begin ReadCommitted
02:45:16.622 16 Y 9 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 12, 0, '2017-01-27 02:45:06', 'ID=12,Name=R548');Select last_insert_rowid() newid
02:45:16.622 16 Y 9 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 11, 0, '2017-01-27 02:45:09', 'ID=11,Name=R486');Select last_insert_rowid() newid
02:45:16.622 16 Y 9 Insert Into Log(Category, [Action], LinkID, CreateUserID, CreateTime, Remark) Values('角色', '添加', 12, 0, '2017-01-27 02:45:12', 'ID=12,Name=R633');Select last_insert_rowid() newid
02:45:16.637 16 Y 9 Transaction.Commit ReadCommitted

 

從測試結果來看:
1,任務1申請得到11和12,任務2也是
2,任務1申請得到11後,任務2啟動,執行到Insert時阻塞了5.12秒,直到任務1回滾了事務
3,線程15和16是非同步寫日誌,顯然它們也被阻塞,線程15阻塞10.519秒,知道任務2提交事務


結論:SQLite執行更新事務操作時使用排它鎖,強制自增數字同步分配!


參考:
http://sqlite.1065341.n5.nabble.com/Transactions-and-sqlite3-last-insert-rowid-td8905.html

 

 

> If I understand it correctly, connection C1 can do an INSERT, get
> ROWID 4, C2 does an INSERT, gets 5, and commits, and then C1 commits,
> with its 4; if C1 rolled back, there's no 4 in the database, just 5
> and whatever else, correct?
>
No, this can't happen. As soon as C1 does its insert, it acquires an
exclusive lock on the database. C2 can't do an insert until C1 either
commits or rolls back and releases the lock. If C1 committed, then C2
will get 5, if C1 rolled back, then C2 will get 4.

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 首先需要引用命名空間 ,同時也需要右擊'引用' --> '添加引用' --> '程式集' --> '框架' --> 'System.Configuration',SqlHelper屬於三層中的DAL層: using System.Data; using System.Data.SqlClient; ...
  • Channel的音頻引擎是我自己寫的,保存文件一直想找開源庫但就是找不著。。 於是就有了以下簡單粗暴打點辦法: 首先是WAV的文件格式: 起始地址 占用空間 本地址數字的含義 00H 4byte RIFF,資源交換文件標誌。 04H 4byte 從下一個地址開始到文件尾的總位元組數。高位位元組在後面,這 ...
  • 起因 在某些情況下,有將從某種類型的語言翻譯成另一種類型語言的需求。比如在生成實體時,可能需要將中文名稱轉換成英文。於是利用CEFSharp山寨了一個翻譯器。效果圖如下: CEF簡介 CEF全稱為Chromium Emmbed Framework,是一個開源項目。用於嵌入基於 Google Chro ...
  • 微信公眾號作為一個平臺級別的產品,對商業應用來說,有很大的吸引力。如何讓公眾號更好的吸粉?靠內容不是一般小商戶可以做到的,那是網紅自媒體的強項。一般商戶要怎麼突圍?那就是提供實用,有意義的功能給粉絲。 而微信公眾號自身功能是非常匱乏的,沒有什麼提供,連客服功能都幾乎沒有,所以這些那些的,就需要開發人 ...
  • 我們十分重視您的隱私。本隱私聲明解釋了我們從您那裡收集的個人數據內容以及我們將如何使用這些數據。 我們不收集任何與個人信息相關的數據,只收集與本UWP運行相關的數據,如: 產品使用數據:如每個頁面的使用次數和相互關係等。 設備數據:您使用的Windows 10設備在本UWP上的唯一設備ID。 錯誤報 ...
  • 需求: 要用WCF生成 Restful風格的介面,返回 JOSN格式: 過程: 1.使用 WCF的 webHttp 綁定。 2.為了增加程式編碼的靈活性,使用了有弱類型特性的 Dictionary<string,object>來作為json字元串對應的類。 3.WCF 預設的序列化不支持 Dicti ...
  • 基本語法 (菜鳥系列學習教程) C#,又名Csharp,天朝喜歡叫C井。 C#是一種面向對象的編程語言。在面向對象的程式設計方法中,程式有各種相互交互的對象組成。相同種類的對象通常具有相同的類型,或者說,是在先溝通那個的class中。 例如,以Rectangle(矩形)對象為例,它具有length和 ...
  • 原文地址:https://mellinoe.wordpress.com/2017/01/18/net core game engine/ 作者:ERIC MELLINO 翻譯: "楊曉東(Savorboard)" 譯者序 通過翻譯這篇文章,我感受到了 .NET Core 真正的魅力,它真的是無所不能 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...