首页 > 编程 > C# > 正文

C#解决SQlite并发异常问题的方法(使用读写锁)

2020-01-24 01:03:40
字体:
来源:转载
供稿:网友

本文实例讲述了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#程序设计有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表