好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

dy("nrwz");

查看更多关于C#解决SQlite并发异常问题的方法(使用读写锁)的详细内容...

  阅读:43次