SQLite在本地存儲方面使用非常廣泛,項目中使用SQLite存儲客戶端消息記錄,本筆記記錄使用過程,同時分享一個常見的錯誤,希望能幫到他人。 ...
前言
客戶端存儲信息的方法有好多種,在以往的項目中採用的是序列化記錄到文件中的方式,即時通信項目中客戶端的一些系統配置的保存也使用的這種方式,然而客戶端保存聊天記錄就不能使用這種方式(保存、讀取、修改都需要進行序列化操作比較費時,不同會話聊天記錄到不同文件中,將需要創建大量的文件),調研相關技術後,決定使用SQLite。
SQLite
我的認知如下:
SQLite是一款輕量級文件資料庫,無需部署安裝,特點是嵌入式與事務(原子性、一致性、隔離性和持久性)。使用時只需創建一個db文件(db文件即代表一個資料庫),然後利用ADO.NET進行連接庫、創建、插入、查詢、修改表就可以了,非常的簡單方便。
步驟
1.添加引用
右鍵項目引用選擇 管理Nuget程式包 搜索SQLite,選擇第一個進行安裝
2.創建資料庫文件
string dbPath = AppDomain.CurrentDomain.BaseDirectory + "local.db"; SQLiteConnection.CreateFile(dbPath);
註意需要添加引用:using System.Data.SQLite;
3.連接SQLite
SQLiteConnection conn = new SQLiteConnection(); SQLiteConnectionStringBuilder connstr = new SQLiteConnectionStringBuilder(); connstr.DataSource = datasource; connstr.Password = "123456";//設置密碼,SQLite ADO.NET實現了資料庫密碼保護 conn.ConnectionString = connstr.ToString(); conn.Open();
4.創建表
SQLiteCommand cmd = new SQLiteCommand(); string sql = "CREATE TABLE FirstTable(ID varchar(36),UserName varchar(30),PassWord varchar(30))"; cmd.CommandText = sql; cmd.Connection = conn; cmd.ExecuteNonQuery();
5.增刪改查
增:
SQLiteCommand cmd = new SQLiteCommand(); string sql = "INSERT INTO FirstTable VALUES('1','ading3','123')"; cmd.Connection = conn; cmd.CommandText = sql; cmd.ExecuteNonQuery();View Code
刪:
string sql = "DELETE FROM FirstTable WHERE ID = @ID"; SQLiteParameter[] parms = { new SQLiteParameter("@ID",id) }; command.CommandText = sql; command.Parameters.AddRange(parameters); int counts = command.ExecuteNonQuery();View Code
改:
string sql= @"UPDATE FirstTable SET UserName=@UserName, PassWord=@PassWord WHERE UserName='admin' "; SQLiteParameter[] parms1 = { new SQLiteParameter("@UserName","adminading"), new SQLiteParameter("@PassWord","2622020") }; command.CommandText = sql; command.Parameters.AddRange(parameters); int counts = command.ExecuteNonQuery();View Code
查:
string query = "SELECT * FROM FirstTable"; DataTable dt = SQLiteHelper.ExecuteQuery(query, null); List<Test> tlist = new List<Test>(); foreach (var item in dt1.Rows) { Test tt = new Test(); tt.ID=(item as DataRow)["ID"].ToString(); tt.UserName = (item as DataRow)["UserName"].ToString(); tt.PassWord = (item as DataRow)["PassWord"].ToString(); tlist.Add(tt); } public class Test { public string ID { get; set; } public string UserName { get; set; } public string PassWord { get; set; } }View Code
幫助類
1 /// <summary> 2 /// SQLite幫助類 3 /// 說明:使用SQLite很簡單,只需要Nuget搜SQLite 使用第一個System.Data.SQLite安裝即可 4 /// 使用CreateDB方法 創建一個資料庫文件 傳入路徑即可 (註意:一個資料庫文件代表一個資料庫) 5 /// 使用前請先指定連接字元串 使用SetConnectionString()方法 6 /// SQLite作為本地文件資料庫 具有獨立運行、無伺服器、零配置、支持事務、低記憶體、原子性等特點 7 /// </summary> 8 public class SQLiteHelper 9 { 10 #region 屬性 11 /// <summary> 12 /// 連接字元串 13 /// </summary> 14 private static string connectionString = string.Empty; 15 #endregion 屬性 16 17 #region 設置連接字元串與創建資料庫文件 18 /// <summary> 19 /// 根據數據源、密碼、版本號設置連接字元串。 20 /// </summary> 21 /// <param name="datasource">數據源。</param> 22 /// <param name="password">密碼。</param> 23 /// <param name="version">版本號(預設為3)。</param> 24 public static void SetConnectionString(string datasource, string password, int version = 3) 25 { 26 connectionString = string.Format("Data Source={0};Version={1};password={2}", 27 datasource, version, password); 28 } 29 30 /// <summary> 31 /// 創建一個資料庫文件。如果存在同名資料庫文件,則會覆蓋。 32 /// </summary> 33 /// <param name="dbName">資料庫文件名。為null或空串時不創建。</param> 34 /// <param name="password">(可選)資料庫密碼,預設為空。</param> 35 /// <exception cref="Exception"></exception> 36 public static void CreateDB(string dbName) 37 { 38 if (!string.IsNullOrEmpty(dbName)) 39 { 40 try 41 { 42 CreateDirectory(dbName); 43 SQLiteConnection.CreateFile(dbName); 44 } 45 catch (Exception ex) 46 { 47 string errormes = ex.Message; 48 errormes += "\r\n"; 49 errormes += LogHelper.ToMessage(ex); 50 string path = string.Empty; 51 path += AppDomain.CurrentDomain.BaseDirectory; 52 path += @"Unlog\SQLiteError"; 53 path += DateTime.Now.ToString("yyyyMMddHHmm"); 54 path += ".txt"; 55 LogHelper.Instance.WriteLog(path, errormes); 56 } 57 } 58 } 59 60 #region 輔助方法 61 /// <summary> 62 /// 創建父級路徑 63 /// </summary> 64 /// <param name="infoPath"></param> 65 private static void CreateDirectory(string infoPath) 66 { 67 DirectoryInfo directoryInfo = Directory.GetParent(infoPath); 68 if (!directoryInfo.Exists) 69 { 70 directoryInfo.Create(); 71 } 72 } 73 #endregion 輔助方法 74 #endregion 設置連接字元串與創建資料庫文件 75 76 #region 命令參數封裝 77 // <summary> 78 /// 準備操作命令參數 79 /// </summary> 80 /// <param name="cmd">SQLiteCommand</param> 81 /// <param name="conn">SQLiteConnection</param> 82 /// <param name="cmdText">Sql命令文本</param> 83 /// <param name="data">參數數組</param> 84 private static void PrepareCommand(SQLiteConnection conn, SQLiteCommand cmd, string cmdText, params SQLiteParameter[] parms) 85 { 86 if (conn.State != ConnectionState.Open) 87 conn.Open(); 88 cmd.Parameters.Clear(); 89 cmd.Connection = conn; 90 cmd.CommandText = cmdText; 91 cmd.CommandType = CommandType.Text; 92 cmd.CommandTimeout = 30; 93 if (parms != null && parms.Length > 0) 94 { 95 foreach (SQLiteParameter parameter in parms) 96 { 97 if ((parameter.Direction == ParameterDirection.Input || parameter.Direction == ParameterDirection.InputOutput) && (parameter.Value == null)) 98 { 99 parameter.Value = DBNull.Value; 100 } 101 } 102 cmd.Parameters.AddRange(parms); 103 } 104 } 105 106 #endregion 命令參數封裝 107 108 #region 資料庫操作 109 #region 創建表 110 /// <summary> 111 /// 創建表 112 /// </summary> 113 /// <param name="sql"></param> 114 /// <returns></returns> 115 public static bool CreateTable(string sql) 116 { 117 bool rr = true; 118 try 119 { 120 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 121 { 122 using (SQLiteCommand command = new SQLiteCommand(connection)) 123 { 124 try 125 { 126 PrepareCommand(connection, command, sql, null); 127 int count = command.ExecuteNonQuery(); 128 if (count > 0) rr = true; 129 else rr = false; 130 } 131 catch (Exception ex) 132 { 133 return false; 134 } 135 } 136 } 137 } 138 catch (Exception ex) 139 { 140 141 return false; 142 } 143 return rr; 144 } 145 #endregion 創建表 146 147 #region 增刪改操作 148 /// <summary> 149 /// 對SQLite資料庫執行增刪改操作,返回受影響的行數。 150 /// </summary> 151 /// <param name="sql">要執行的增刪改的SQL語句。</param> 152 /// <param name="parameters">執行增刪改語句所需要的參數,參數必須以它們在SQL語句中的順序為準。</param> 153 /// <returns></returns> 154 /// <exception cref="Exception"></exception> 155 public static int ExecuteNonQuery(string sql, params SQLiteParameter[] parameters) 156 { 157 int affectedRows = 0; 158 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 159 { 160 using (SQLiteCommand command = new SQLiteCommand(connection)) 161 { 162 try 163 { 164 PrepareCommand(connection, command, sql, parameters); 165 //connection.Open(); 166 //command.CommandText = sql; 167 //if (parameters.Length != 0) 168 //{ 169 // command.Parameters.AddRange(parameters); 170 //} 171 affectedRows = command.ExecuteNonQuery(); 172 } 173 catch (Exception) { throw; } 174 } 175 } 176 return affectedRows; 177 } 178 #endregion 增刪改操作 179 180 #region 批量操作 181 /// <summary> 182 /// 批量處理數據操作語句。 183 /// </summary> 184 /// <param name="list">SQL語句集合。</param> 185 /// <exception cref="Exception"></exception> 186 public static void ExecuteNonQueryBatch(List<KeyValuePair<string, SQLiteParameter[]>> list) 187 { 188 using (SQLiteConnection conn = new SQLiteConnection(connectionString)) 189 { 190 try { conn.Open(); } 191 catch { throw; } 192 using (SQLiteTransaction tran = conn.BeginTransaction()) 193 { 194 using (SQLiteCommand cmd = new SQLiteCommand(conn)) 195 { 196 try 197 { 198 foreach (var item in list) 199 { 200 PrepareCommand(conn, cmd, item.Key, item.Value); 201 //cmd.CommandText = item.Key; 202 //if (item.Value != null) 203 //{ 204 // cmd.Parameters.AddRange(item.Value); 205 //} 206 cmd.ExecuteNonQuery(); 207 } 208 tran.Commit(); 209 } 210 catch (Exception) { tran.Rollback(); throw; } 211 } 212 } 213 } 214 } 215 #endregion 批量操作 216 217 #region 查詢 返回第一個 218 /// <summary> 219 /// 執行查詢語句,並返回第一個結果。 220 /// </summary> 221 /// <param name="sql">查詢語句。</param> 222 /// <returns>查詢結果。</returns> 223 /// <exception cref="Exception"></exception> 224 public static object ExecuteScalar(string sql, params SQLiteParameter[] parameters) 225 { 226 using (SQLiteConnection conn = new SQLiteConnection(connectionString)) 227 { 228 using (SQLiteCommand cmd = new SQLiteCommand(conn)) 229 { 230 try 231 { 232 PrepareCommand(conn, cmd, sql, parameters); 233 //conn.Open(); 234 //cmd.CommandText = sql; 235 //if (parameters.Length != 0) 236 //{ 237 // cmd.Parameters.AddRange(parameters); 238 //} 239 return cmd.ExecuteScalar(); 240 } 241 catch (Exception) { throw; } 242 } 243 } 244 } 245 #endregion 查詢 返回第一個 246 247 #region 查詢 返回DT 248 /// <summary> 249 /// 執行一個查詢語句,返回一個包含查詢結果的DataTable。 250 /// </summary> 251 /// <param name="sql">要執行的查詢語句。</param> 252 /// <param name="parameters">執行SQL查詢語句所需要的參數,參數必須以它們在SQL語句中的順序為準。</param> 253 /// <returns></returns> 254 /// <exception cref="Exception"></exception> 255 public static DataTable ExecuteQuery(string sql, params SQLiteParameter[] parameters) 256 { 257 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 258 { 259 using (SQLiteCommand command = new SQLiteCommand(sql, connection)) 260 { 261 PrepareCommand(connection, command, sql, parameters); 262 //if (parameters != null) 263 //{ 264 // if (parameters.Length != 0) 265 // { 266 // command.Parameters.AddRange(parameters); 267 // } 268 //} 269 270 SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); 271 DataTable data = new DataTable(); 272 try { adapter.Fill(data); } 273 catch (Exception) { throw; } 274 return data; 275 } 276 } 277 } 278 #endregion 查詢 返回DT 279 280 #region 查詢 返回SQLiteDataReader 281 /// <summary> 282 /// 執行一個查詢語句,返回一個關聯的SQLiteDataReader實例。 283 /// </summary> 284 /// <param name="sql">要執行的查詢語句。</param> 285 /// <param name="parameters">執行SQL查詢語句所需要的參數,參數必須以它們在SQL語句中的順序為準。</param> 286 /// <returns></returns> 287 /// <exception cref="Exception"></exception> 288 public static SQLiteDataReader ExecuteReader(string sql, params SQLiteParameter[] parameters) 289 { 290 SQLiteConnection connection = new SQLiteConnection(connectionString); 291 SQLiteCommand command = new SQLiteCommand(sql, connection); 292 try 293 { 294 PrepareCommand(connection, command, sql, parameters); 295 //if (parameters.Length != 0) 296 //{ 297 // command.Parameters.AddRange(parameters); 298 //} 299 //connection.Open(); 300 return command.ExecuteReader(CommandBehavior.CloseConnection); 301 } 302 catch (Exception) { throw; } 303 } 304 #endregion 查詢 返回SQLiteDataReader 305 306 #region 查詢資料庫中的所有數據類型信息 307 /// <summary> 308 /// 查詢資料庫中的所有數據類型信息。 309 /// </summary> 310 /// <returns></returns> 311 /// <exception cref="Exception"></exception> 312 public static DataTable GetSchema() 313 { 314 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 315 { 316 try 317 { 318 connection.Open(); 319 return connection.GetSchema("TABLES"); 320 } 321 catch (Exception) { throw; } 322 } 323 } 324 325 #endregion 查詢資料庫中的所有數據類型信息 326 327 #region 判斷表是否存在 328 public static bool IsTableExist(string tableName) 329 { 330 bool isTableExist = true; 331 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 332 { 333 string sql = "SELECT name FROM sqlite_master WHERE type='table' AND name = '"; 334 sql += tableName; 335 sql += "'"; 336 using (SQLiteCommand command = new SQLiteCommand(sql, connection)) 337 { 338 PrepareCommand(connection, command, sql, null); 339 int count = command.ExecuteNonQuery(); 340 if (count <= 0) isTableExist = false; 341 } 342 } 343 return isTableExist; 344 345 } 346 #endregion 判斷表是否存在 347 348 #endregion 資料庫操作 349 350 #region 整理資料庫 351 /// <summary> 352 /// 重新組織資料庫 353 /// SQLite 的自帶命令 VACUUM。用來重新整理整個資料庫達到緊湊之用,比如把刪除的徹底刪掉等等 354 /// </summary> 355 public static void ResetDataBass() 356 { 357 using (SQLiteConnection conn = new SQLiteConnection(connectionString)) 358 { 359 var cmd = new SQLiteCommand(); 360 361 if (conn.State != ConnectionState.Open) 362 conn.Open(); 363 cmd.Parameters.Clear(); 364 cmd.Connection = conn; 365 cmd.CommandText = "vacuum"; 366