时间:2021-05-20
本文实例讲述了C#解决SQlite并发异常问题的方法。分享给大家供大家参考,具体如下:
使用C#访问sqlite时,常会遇到多线程并发导致SQLITE数据库损坏的问题。
SQLite是文件级别的数据库,其锁也是文件级别的:多个线程可以同时读,但是同时只能有一个线程写。Android提供了SqliteOpenHelper类,加入Java的锁机制以便调用。但在C#中未提供类似功能。
作者利用读写锁(ReaderWriterLock),达到了多线程安全访问的目标。
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 // 手动控制销毁,保证数据完整性 public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected void Dispose(bool disposing) { if (!m_disposed) { if (disposing) { // Release managed resources Console.WriteLine("关闭本地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("严重异常: 无法关闭本地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}}////////////////////////调用的代码如下:
SQLiteConnection conn = null;try{ conn = SqliteConn.GetInstance().GetConnection(); //在这里写自己的代码}finally{ SqliteConn.GetInstance().ReleaseConn();}值得注意的是,每次申请连接后,必须使用ReleaseConn方法释放,否则其它线程就再也无法得到连接了。
安全起见,在作者写的这个工具类中,启用了最严格的读写锁限制(即在写入时无法读取)。如果数据读取频繁,读者亦可开发一个得到只读连接的方法以提高性能。
在Winxp/Win7/Win8/Win8.1 32/64位下测试通过。
更多关于C#相关内容感兴趣的读者可查看本站专题:《C#程序设计之线程使用技巧总结》、《C#操作Excel技巧总结》、《C#中XML文件操作技巧汇总》、《C#常见控件用法教程》、《WinForm控件用法总结》、《C#数据结构与算法教程》、《C#数组操作技巧总结》及《C#面向对象程序设计入门教程》
希望本文所述对大家C#程序设计有所帮助。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文实例讲述了C#中增加SQLite事务操作支持与使用方法。分享给大家供大家参考,具体如下:在C#中使用Sqlite增加对transaction支持usingS
本文实例讲述了C#操作SQLite数据库之读写数据库的方法。分享给大家供大家参考,具体如下:这里演示读写数据库并在窗体(Form)中显示其数据,其方式为:读:D
读写锁的概念很简单,允许多个线程同时获取读锁,但同一时间只允许一个线程获得写锁,因此也称作共享-独占锁。在C#中,推荐使用ReaderWriterLockSli
本文实例讲述了C#封装的Sqlite访问类。分享给大家供大家参考。具体分析如下:C#封装的Sqlite访问类,要访问Sqlite这下简单了,直接调用此类中的方法
SQLite支持3种线程模式: 单线程:这种模式下,没有进行互斥,多线程使用不安全。禁用所有的mutex锁,并发使用时会出错。当SQLite编译时加了SQLI