C#解決SQlite并發(fā)異常問題的方法(使用讀寫鎖)
本文實(shí)例講述了C#解決SQlite并發(fā)異常問題的方法。分享給大家供大家參考,具體如下:
使用C#訪問sqlite時,常會遇到多線程并發(fā)導(dǎo)致SQLITE數(shù)據(jù)庫損壞的問題。
SQLite是文件級別的數(shù)據(jù)庫,其鎖也是文件級別的:多個線程可以同時讀,但是同時只能有一個線程寫。Android提供了SqliteOpenHelper類,加入Java的鎖機(jī)制以便調(diào)用。但在C#中未提供類似功能。
作者利用讀寫鎖(ReaderWriterLock),達(dá)到了多線程安全訪問的目標(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("嚴(yán)重異常: 無法關(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方法釋放,否則其它線程就再也無法得到連接了。
安全起見,在作者寫的這個工具類中,啟用了最嚴(yán)格的讀寫鎖限制(即在寫入時無法讀取)。如果數(shù)據(jù)讀取頻繁,讀者亦可開發(fā)一個得到只讀連接的方法以提高性能。
在Winxp/Win7/Win8/Win8.1 32/64位下測試通過。
更多關(guān)于C#相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《C#程序設(shè)計(jì)之線程使用技巧總結(jié)》、《C#操作Excel技巧總結(jié)》、《C#中XML文件操作技巧匯總》、《C#常見控件用法教程》、《WinForm控件用法總結(jié)》、《C#數(shù)據(jù)結(jié)構(gòu)與算法教程》、《C#數(shù)組操作技巧總結(jié)》及《C#面向?qū)ο蟪绦蛟O(shè)計(jì)入門教程》
希望本文所述對大家C#程序設(shè)計(jì)有所幫助。
欄 目:C#教程
下一篇:C#獲取機(jī)器碼的方法詳解(機(jī)器名,CPU編號,硬盤編號,網(wǎng)卡mac等)
本文標(biāo)題:C#解決SQlite并發(fā)異常問題的方法(使用讀寫鎖)
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/6357.html
您可能感興趣的文章
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10C#刪除只讀文件或文件夾(解決File.Delete無法刪除文件)
- 01-10C# readnodefile()不能讀取帶有文件名為漢字的osg文件解決方法
- 01-10c#讀寫App.config,ConfigurationManager.AppSettings 不生效的解決方法
- 01-10ASP.NET MVC命名空間時引起錯誤的解決方法
- 01-10當(dāng)用戶退出點(diǎn)擊瀏覽器后退仍可回到原來頁面的解決方案
- 01-10C#解析json字符串總是多出雙引號的原因分析及解決辦法
- 01-10C#進(jìn)階系列 WebApi身份認(rèn)證解決方案推薦:Basic基礎(chǔ)認(rèn)證
- 01-10vista和win7在windows服務(wù)中交互桌面權(quán)限問題解決方法:穿透Sessi
- 01-10SMTP客戶端未通過身份驗(yàn)證等多種錯誤解決方案分享


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實(shí)例總結(jié)
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置


