SQLite作为一个本地文件数据库相当好用,小巧、快速、支持事务、关系型,甚至可以运行在Android上。在很久以前的一个项目中,我们用过它来将接收到的数据做本地统计,数据量很大,甚至于我们想自己搞个内存空间专门做缓存,缓存满后再一点点地往SQLite中移,现在看起来是多余的,这也不符合开发的过程。在开发中,应该先把功能做出来,如果有性能问题,再找出解决方法。直接在SQLite中做插入而不是先在内存中做,它的效率已经达到了要求。
现在跟大家分享一个对SQLite操作的帮助类,使用它可以对本地SQLite数据库进行方便的操作。
如有引用,注意写明转自:http://www.cnblogs.com/wgp13x/p/3868916.html
关键词:SQLite, C#, sqlite3.dll, SQLite Expert
摘要:SQLite作为一个本地文件数据库相当好用,小巧、快速、支持事务、关系型,在之前的一个项目中使用了它,现在把这使用经验总结一下,分享给大家。
1 using System; 2 using System.Data.SQLite; 3 using System.Data; 4 using System.Data.Common; 5 6 namespace DXPlatformClientFramework.UC.StatAnalyzeCommon 7 { 8 public class SqliteHelper : IDisposable 9 { 10 public SQLiteConnection conn; 11 12 public void Dispose() 13 { 14 Dispose(true); 15 GC.SuppressFinalize(this); 16 } 17 18 protected virtual void Dispose(bool disposing) 19 { 20 if(disposing) 21 if(conn != null) 22 { 23 conn.Dispose(); 24 conn = null; 25 } 26 } 27 28 ~SqliteHelper() 29 { 30 Dispose(false); 31 } 32 33 /// <summary> 34 /// 构造函数。 35 /// </summary> 36 /// <param name="dataBaseName">数据库名</param> 37 public SqliteHelper(string dataBaseName) 38 { 39 string connString = string.Format(@"Data Source={0}", dataBaseName); 40 conn = new SQLiteConnection(connString); 41 conn.Open(); 42 } 43 44 /// <summary> 45 /// 手动打开数据库。 46 /// </summary> 47 public void SqliteOpen() 48 { 49 if(conn != null && conn.State == ConnectionState.Closed) 50 conn.Open(); 51 } 52 53 /// <summary> 54 /// 通过执行SQL语句,获取表中数据。 55 /// </summary> 56 /// <param name="sError">错误信息</param> 57 /// <param name="sSQL">执行的SQL语句</param> 58 public DataTable GetDataTable(out string sError, string sSQL) 59 { 60 DataTable dt = null; 61 sError = string.Empty; 62 try 63 { 64 SQLiteCommand cmd = newSQLiteCommand() { CommandText = sSQL, Connection = conn }; 65 SQLiteDataAdapter dao = newSQLiteDataAdapter(cmd); 66 dt = newDataTable(); 67 dao.Fill(dt); 68 } 69 catch(Exception e) 70 { 71 sError = e.Message; 72 } 73 return dt; 74 } 75 76 /// <summary> 77 /// 通过执行SQL语句,获取表中数据个数。 78 /// </summary> 79 /// <param name="sError">错误信息</param> 80 /// <param name="sSQL">执行的SQL语句</param> 81 public int GetDataCount(out string sError, string sSQL) 82 { 83 DataTable dt = newDataTable(); 84 sError = string.Empty; 85 SQLiteCommand cmd = newSQLiteCommand() { CommandText = sSQL, Connection = conn }; 86 try 87 { 88 SQLiteDataAdapter dao = new SQLiteDataAdapter(cmd); 89 dao.Fill(dt); 90 cmd.Dispose(); 91 } 92 catch(Exception e) 93 { 94 sError = e.Message; 95 } 96 finally{ cmd.Dispose(); } 97 return int.Parse(dt.Rows[0][0].ToString()); 98 } 99 100 /// <summary> 101 /// 通过执行SQL语句,执行insert,update,delete 动作,也可以使用事务。 102 /// </summary> 103 /// <param name="sError">错误信息</param> 104 /// <param name="sSQL">执行的SQL语句</param> 105 /// <param name="bUseTransaction">是否使用事务</param> 106 public bool UpdateData(out string sError, string sSQL, bool bUseTransaction=false) 108 { 109 bool iResult = false; 110 sError = string.Empty; 111 if(!bUseTransaction) 112 { 113 try 114 { 115 SQLiteCommand comm = new SQLiteCommand(conn) { CommandText = sSQL }; 116 iResult = comm.ExecuteNonQuery()>0; 117 comm.Dispose(); 118 } 119 catch(Exception ex) 120 { 121 sError = ex.Message; 122 } 123 } 124 else// 使用事务 125 { 126 DbTransaction trans = null; 127 trans = conn.BeginTransaction(); 128 SQLiteCommand comm = new SQLiteCommand(conn) { CommandText = sSQL }; 129 try 130 { 131 iResult = comm.ExecuteNonQuery()>0; 132 trans.Commit(); 133 } 134 catch(Exception ex) 135 { 136 sError = ex.Message; 137 iResult = false; 138 trans.Rollback(); 139 } 140 finally{comm.Dispose();trans.Dispose();} 141 } 142 return iResult; 143 } 144 145 /// <summary> 146 /// 使用事务执行多条相同的带参数的SQL语句。 147 /// </summary> 148 /// <param name="sqlString">SQL语句</param> 149 /// <param name="sqLiteParameters">每次SQL执行的参数</param> 150 public void ExecuteSqlTran(string sqlString, object[][] sqLiteParameters) 151 { 152 if(sqLiteParameters.Length == 0) 153 return; 154 using(DbTransaction trans = conn.BeginTransaction()) 155 { 156 if(conn.State != ConnectionState.Open) 157 conn.Open(); 158 SQLiteCommand cmd = conn.CreateCommand(); 159 cmd.Connection = conn; 160 try 161 { 162 for(inti = 0; i < sqLiteParameters[0].Length; i++) 163 { 164 cmd.Parameters.Add(cmd.CreateParameter()); 165 } 166 //循环 167 foreach(object[] sqlParameters insqLiteParameters) 168 { 169 ExecuteSqlNonQuery(cmd, sqlString, sqlParameters); 170 } 171 trans.Commit(); 172 } 173 catch(Exception ex) 174 { 175 trans.Rollback(); 176 throw; 177 } 178 finally 179 { 180 cmd.Dispose();trans.Dispose(); 181 } 182 } 183 } 184 185 /// <summary> 186 /// 不使用事务执行一条带参数的SQL语句。 187 /// </summary> 188 /// <param name="sqlString">SQL语句</param> 189 /// <param name="sqLiteParameters">SQL执行的参数</param> 190 public void ExecuteSql(string sqlString, object[] sqLiteParameters) 191 { 192 if(conn.State != ConnectionState.Open) 193 conn.Open(); 194 SQLiteCommand cmd = conn.CreateCommand(); 195 cmd.Connection = conn; 196 cmd.CommandText = sqlString; 197 try 198 { 199 for(inti = 0; i < sqLiteParameters.Length; i++) 200 { 201 cmd.Parameters.Add(cmd.CreateParameter()); 202 cmd.Parameters[i].Value = sqLiteParameters[i]; 203 } 204 cmd.ExecuteNonQuery(); 205 } 206 finally 207 { 208 cmd.Dispose(); 209 } 210 } 211 212 private void ExecuteSqlNonQuery(SQLiteCommand cmd, string cmdText, object[] cmdParms) 214 { 215 cmd.CommandText = cmdText; 216 if(cmdParms != null) 217 { 218 for(inti = 0; i < cmdParms.Length; i++ ) 219 { 220 cmd.Parameters[i].Value = cmdParms[i]; 221 } 222 } 223 cmd.ExecuteNonQuery(); 224 } 225 } 226 }
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本身应该提供了多线程访问的支持。
之后的多线程开发就是使用了线程安全的集合,代码结构简单。