C#解決SQlite并發(fā)異常問題的方法(使用讀寫鎖)
本文實例講述了C#解決SQlite并發(fā)異常問題的方法。分享給大家供大家參考,具體如下:
使用C#訪問sqlite時,常會遇到多線程并發(fā)導(dǎo)致SQLITE數(shù)據(jù)庫損壞的問題。
SQLite是文件級別的數(shù)據(jù)庫,其鎖也是文件級別的:多個線程可以同時讀,但是同時只能有一個線程寫。Android提供了SqliteOpenHelper類,加入Java的鎖機制以便調(diào)用。但在C#中未提供類似功能。
作者利用讀寫鎖(ReaderWriterLock),達到了多線程安全訪問的目標(biāo)。
using System; using System.Collections.Generic; using System.Text; using System.Data.SQLite; using System.Threading; using System.Data; namespace DataAccess { ///////////////// public sealed class SqliteConn { private bool m_disposed; private static Dictionary<String, SQLiteConnection> connPool = new Dictionary<string, SQLiteConnection>(); private static Dictionary<String, ReaderWriterLock> rwl = new Dictionary<String, ReaderWriterLock>(); private static readonly SqliteConn instance = new SqliteConn(); private static string DEFAULT_NAME = "LOCAL"; #region Init // 使用單例,解決初始化與銷毀時的問題 private SqliteConn() { rwl.Add("LOCAL", new ReaderWriterLock()); rwl.Add("DB1", new ReaderWriterLock()); connPool.Add("LOCAL", CreateConn("\\local.db")); connPool.Add("DB1", CreateConn("\\db1.db")); Console.WriteLine("INIT FINISHED"); } private static SQLiteConnection CreateConn(string dbName) { SQLiteConnection _conn = new SQLiteConnection(); try { string pstr = "pwd"; SQLiteConnectionStringBuilder connstr = new SQLiteConnectionStringBuilder(); connstr.DataSource = Environment.CurrentDirectory + dbName; _conn.ConnectionString = connstr.ToString(); _conn.SetPassword(pstr); _conn.Open(); return _conn; } catch (Exception exp) { Console.WriteLine("===CONN CREATE ERR====\r\n{0}", exp.ToString()); return null; } } #endregion #region Destory // 手動控制銷毀,保證數(shù)據(jù)完整性 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected void Dispose(bool disposing) { if (!m_disposed) { if (disposing) { // Release managed resources Console.WriteLine("關(guān)閉本地DB連接..."); CloseConn(); } // Release unmanaged resources m_disposed = true; } } ~SqliteConn() { Dispose(false); } public void CloseConn() { foreach (KeyValuePair<string, SQLiteConnection> item in connPool) { SQLiteConnection _conn = item.Value; String _connName = item.Key; if (_conn != null && _conn.State != ConnectionState.Closed) { try { _conn.Close(); _conn.Dispose(); _conn = null; Console.WriteLine("Connection {0} Closed.", _connName); } catch (Exception exp) { Console.WriteLine("嚴重異常: 無法關(guān)閉本地DB {0} 的連接。", _connName); exp.ToString(); } finally { _conn = null; } } } } #endregion #region GetConn public static SqliteConn GetInstance() { return instance; } public SQLiteConnection GetConnection(string name) { SQLiteConnection _conn = connPool[name]; try { if (_conn != null) { Console.WriteLine("TRY GET LOCK"); //加鎖,直到釋放前,其它線程無法得到conn rwl[name].AcquireWriterLock(3000); Console.WriteLine("LOCK GET"); return _conn; } } catch (Exception exp) { Console.WriteLine("===GET CONN ERR====\r\n{0}", exp.StackTrace); } return null; } public void ReleaseConn(string name) { try { //釋放 Console.WriteLine("RELEASE LOCK"); rwl[name].ReleaseLock(); } catch (Exception exp) { Console.WriteLine("===RELEASE CONN ERR====\r\n{0}", exp.StackTrace); } } public SQLiteConnection GetConnection() { return GetConnection(DEFAULT_NAME); } public void ReleaseConn() { ReleaseConn(DEFAULT_NAME); } #endregion } } ////////////////////////
調(diào)用的代碼如下:
SQLiteConnection conn = null; try { conn = SqliteConn.GetInstance().GetConnection(); //在這里寫自己的代碼 } finally { SqliteConn.GetInstance().ReleaseConn(); }
值得注意的是,每次申請連接后,必須使用ReleaseConn方法釋放,否則其它線程就再也無法得到連接了。
安全起見,在作者寫的這個工具類中,啟用了最嚴格的讀寫鎖限制(即在寫入時無法讀?。?。如果數(shù)據(jù)讀取頻繁,讀者亦可開發(fā)一個得到只讀連接的方法以提高性能。
在Winxp/Win7/Win8/Win8.1 32/64位下測試通過。
更多關(guān)于C#相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《C#程序設(shè)計之線程使用技巧總結(jié)》、《C#操作Excel技巧總結(jié)》、《C#中XML文件操作技巧匯總》、《C#常見控件用法教程》、《WinForm控件用法總結(jié)》、《C#數(shù)據(jù)結(jié)構(gòu)與算法教程》、《C#數(shù)組操作技巧總結(jié)》及《C#面向?qū)ο蟪绦蛟O(shè)計入門教程》
希望本文所述對大家C#程序設(shè)計有所幫助。
相關(guān)文章
C#調(diào)用和實現(xiàn)WebService,純手工打造!
C#調(diào)用和實現(xiàn)WebService,純手工打造! 需要的朋友可以參考一下2013-02-02spreadsheetgear插件屏蔽鼠標(biāo)右鍵的方法
今天用到spreadsheetGear插件,然后右鍵有插件自己的菜單。都是英文的,而且還能打開新的窗體。嵌到程序里面,不太合適,所以著手屏蔽2014-02-02常用.NET工具(包括.NET可再發(fā)行包2.0)下載
常用.NET工具(包括.NET可再發(fā)行包2.0)下載...2007-03-03C#多線程學(xué)習(xí)之(五)使用定時器進行多線程的自動管理
這篇文章主要介紹了C#多線程學(xué)習(xí)之使用定時器進行多線程的自動管理,實例分析了C#使用timer定時器類實現(xiàn)針對多線程的自動管理功能,非常具有實用價值,需要的朋友可以參考下2015-04-04