SQLite作为一个本地文件数据库相当好用,小巧、快速、支持事务、关系型,甚至可以运行在Android上。在很久以前的一个项目中,我们用过它来将接收到的数据做本地统计,数据量很大,甚至于我们想自己搞个内存空间专门做缓存,缓存满后再一点点地往SQLite中移,现在看起来是多余的,这也不符合开发的过程。在开发中,应该先把功能做出来,如果有性能问题,再找出解决方法。直接在SQLite中做插入而不是先在内存中做,它的效率已经达到了要求。
现在跟大家分享一个对SQLite操作的帮助类,使用它可以对本地SQLite数据库进行方便的操作。
如有引用,注意写明转自:http://www.cnblogs.com/wgp13x/p/3868916.html
关键词:SQLite, C#, sqlite3.dll, SQLite Expert
摘要:SQLite作为一个本地文件数据库相当好用,小巧、快速、支持事务、关系型,在之前的一个项目中使用了它,现在把这使用经验总结一下,分享给大家。
using System;
using System.Data.SQLite;
using System.Data;
using System.Data.Common; namespace DXPlatformClientFramework.UC.StatAnalyzeCommon
{
public class SqliteHelper : IDisposable
{
public SQLiteConnection conn; public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} protected virtual void Dispose(bool disposing)
{
if(disposing)
if(conn != null)
{
conn.Dispose();
conn = null;
}
} ~SqliteHelper()
{
Dispose(false);
} /// <summary>
/// 构造函数。
/// </summary>
/// <param name="dataBaseName">数据库名</param>
public SqliteHelper(string dataBaseName)
{
string connString = string.Format(@"Data Source={0}", dataBaseName);
conn = new SQLiteConnection(connString);
conn.Open();
} /// <summary>
/// 手动打开数据库。
/// </summary>
public void SqliteOpen()
{
if(conn != null && conn.State == ConnectionState.Closed)
conn.Open();
} /// <summary>
/// 通过执行SQL语句,获取表中数据。
/// </summary>
/// <param name="sError">错误信息</param>
/// <param name="sSQL">执行的SQL语句</param>
public DataTable GetDataTable(out string sError, string sSQL)
{
DataTable dt = null;
sError = string.Empty;
try
{
SQLiteCommand cmd = newSQLiteCommand() { CommandText = sSQL, Connection = conn };
SQLiteDataAdapter dao = newSQLiteDataAdapter(cmd);
dt = newDataTable();
dao.Fill(dt);
}
catch(Exception e)
{
sError = e.Message;
}
return dt;
} /// <summary>
/// 通过执行SQL语句,获取表中数据个数。
/// </summary>
/// <param name="sError">错误信息</param>
/// <param name="sSQL">执行的SQL语句</param>
public int GetDataCount(out string sError, string sSQL)
{
DataTable dt = newDataTable();
sError = string.Empty;
SQLiteCommand cmd = newSQLiteCommand() { CommandText = sSQL, Connection = conn };
try
{
SQLiteDataAdapter dao = new SQLiteDataAdapter(cmd);
dao.Fill(dt);
cmd.Dispose();
}
catch(Exception e)
{
sError = e.Message;
}
finally{ cmd.Dispose(); }
return int.Parse(dt.Rows[][].ToString());
} /// <summary>
/// 通过执行SQL语句,执行insert,update,delete 动作,也可以使用事务。
/// </summary>
/// <param name="sError">错误信息</param>
/// <param name="sSQL">执行的SQL语句</param>
/// <param name="bUseTransaction">是否使用事务</param>
public bool UpdateData(out string sError, string sSQL, bool bUseTransaction=false)
{
bool iResult = false;
sError = string.Empty;
if(!bUseTransaction)
{
try
{
SQLiteCommand comm = new SQLiteCommand(conn) { CommandText = sSQL };
iResult = comm.ExecuteNonQuery()>;
comm.Dispose();
}
catch(Exception ex)
{
sError = ex.Message;
}
}
else// 使用事务
{
DbTransaction trans = null;
trans = conn.BeginTransaction();
SQLiteCommand comm = new SQLiteCommand(conn) { CommandText = sSQL };
try
{
iResult = comm.ExecuteNonQuery()>;
trans.Commit();
}
catch(Exception ex)
{
sError = ex.Message;
iResult = false;
trans.Rollback();
}
finally{comm.Dispose();trans.Dispose();}
}
return iResult;
} /// <summary>
/// 使用事务执行多条相同的带参数的SQL语句。
/// </summary>
/// <param name="sqlString">SQL语句</param>
/// <param name="sqLiteParameters">每次SQL执行的参数</param>
public void ExecuteSqlTran(string sqlString, object[][] sqLiteParameters)
{
if(sqLiteParameters.Length == )
return;
using(DbTransaction trans = conn.BeginTransaction())
{
if(conn.State != ConnectionState.Open)
conn.Open();
SQLiteCommand cmd = conn.CreateCommand();
cmd.Connection = conn;
try
{
for(inti = ; i < sqLiteParameters[].Length; i++)
{
cmd.Parameters.Add(cmd.CreateParameter());
}
//循环
foreach(object[] sqlParameters insqLiteParameters)
{
ExecuteSqlNonQuery(cmd, sqlString, sqlParameters);
}
trans.Commit();
}
catch(Exception ex)
{
trans.Rollback();
throw;
}
finally
{
cmd.Dispose();trans.Dispose();
}
}
} /// <summary>
/// 不使用事务执行一条带参数的SQL语句。
/// </summary>
/// <param name="sqlString">SQL语句</param>
/// <param name="sqLiteParameters">SQL执行的参数</param>
public void ExecuteSql(string sqlString, object[] sqLiteParameters)
{
if(conn.State != ConnectionState.Open)
conn.Open();
SQLiteCommand cmd = conn.CreateCommand();
cmd.Connection = conn;
cmd.CommandText = sqlString;
try
{
for(inti = ; i < sqLiteParameters.Length; i++)
{
cmd.Parameters.Add(cmd.CreateParameter());
cmd.Parameters[i].Value = sqLiteParameters[i];
}
cmd.ExecuteNonQuery();
}
finally
{
cmd.Dispose();
}
} private void ExecuteSqlNonQuery(SQLiteCommand cmd, string cmdText, object[] cmdParms)
{
cmd.CommandText = cmdText;
if(cmdParms != null)
{
for(inti = ; i < cmdParms.Length; i++ )
{
cmd.Parameters[i].Value = cmdParms[i];
}
}
cmd.ExecuteNonQuery();
}
}
}
SQLite的语法跟标准的SQL语法不太一样,比如isnull(x, y) --> 如果x为空则应该返回y,SQLite就不支持,取代的是ifnull(x, y),使用起来也很方便。
这里提供了C#版本的的操作代码,JAVA版本的也差不多。
做了这个项目,回头看以前写的代码,惨不忍睹,太烂。尤其是关于C#多线程的,线程之间同步处理的一笔吊糟,经常缝缝补补,代码逻辑混乱。
做完后自己就立马总结了一下,关于多线程的同步,不到万不得以,不要自己做。
lock (BackWorker.ProduceLocker) { Monitor.Pulse(BackWorker.ProduceLocker); }
lock (BackWorker.ConsumeLocker) { Monitor.Wait(BackWorker.ConsumeLocker); }
这类的,非常容易把自己绕进去,而且脱离了面向对象的思想。
多线程同步无非是因为多个线程同时对同一份数据有了同时操作,它们之间得分出个先后次序来,
这在JAVA中提供了线程安全的集合在java.util.concurrent包中,这就不需要自己在线程中手动做同步了,这也非常符合面向对象的思想。
SQLite本身应该提供了多线程访问的支持。
之后的多线程开发就是使用了线程安全的集合,代码结构简单。