為什麼選 SQLite?
- ✅ **零配置**:單一檔案 (
.db/.sqlite),無服務程序,XCOPY 部署。
- ✅ **ACID 事務**:斷電、崩潰後資料一致性有保障,優於 Access/純文字檔。
- ✅ **輕量**:核心 < 300 KB,嵌入式裝置、行動應用、桌面工具皆宜。
- ✅ **跨平台**:.NET Framework / .NET Core / Xamarin / Unity 通用。
- ✅ **ADO.NET 標準介面**:
System.Data.SQLite 完整實作 DbConnection、DbCommand 等,既有程式碼零成本遷移。
一、環境建置
- NuGet 安裝:
Install-Package System.Data.SQLite (含原生 DLL 自動部署)。
- .NET Framework 專案需在
App.config 啟用舊版執行階段啟用政策(混合模式組件需求):
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
</startup>
</configuration>
二、Visual Studio 整合操作
- **伺服器總管** → **加入連線** → 資料來源選 **SQLite Database File** → 建立/選擇
.db 檔。
- 支援資料表設計、查詢編輯器、資料檢視,體驗如同 SQL Server。
三、通用 SQLiteHelper 封裝
using System;
using System.Data;
using System.Data.Common;
using System.Data.SQLite;
public static class SQLiteHelper
{
public static string ConnectionString { get; set; }
= "Data Source=AppData.db;Pooling=true;FailIfMissing=false;";
private static void PrepareCommand(SQLiteCommand cmd, SQLiteConnection conn,
string sql, params object[] parameters)
{
if (conn.State != ConnectionState.Open) conn.Open();
cmd.Parameters.Clear();
cmd.Connection = conn;
cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = 30;
if (parameters != null)
{
for (int i = 0; i < parameters.Length; i++)
cmd.Parameters.AddWithValue($"@p{i}", parameters[i]);
}
}
public static DataSet ExecuteQuery(string sql, params object[] p)
{
using (var conn = new SQLiteConnection(ConnectionString))
using (var cmd = new SQLiteCommand())
{
PrepareCommand(cmd, conn, sql, p);
var ds = new DataSet();
new SQLiteDataAdapter(cmd).Fill(ds);
return ds;
}
}
public static int ExecuteNonQuery(string sql, params object[] p)
{
using (var conn = new SQLiteConnection(ConnectionString))
using (var cmd = new SQLiteCommand())
{
PrepareCommand(cmd, conn, sql, p);
return cmd.ExecuteNonQuery();
}
}
public static SQLiteDataReader ExecuteReader(string sql, params object[] p)
{
var conn = new SQLiteConnection(ConnectionString);
var cmd = new SQLiteCommand();
PrepareCommand(cmd, conn, sql, p);
// Caller 負責關閉 reader 並 dispose conn (CommandBehavior.CloseConnection)
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
public static object ExecuteScalar(string sql, params object[] p)
{
using (var conn = new SQLiteConnection(ConnectionString))
using (var cmd = new SQLiteCommand())
{
PrepareCommand(cmd, conn, sql, p);
return cmd.ExecuteScalar();
}
}
}
四、使用範例
// 建表
SQLiteHelper.ExecuteNonQuery(@"
CREATE TABLE IF NOT EXISTS Users (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Email TEXT UNIQUE,
CreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP
);");
// 新增
int rows = SQLiteHelper.ExecuteNonQuery(
"INSERT INTO Users (Name, Email) VALUES (@p0, @p1)", "Alice", "alice@example.com");
// 查詢
var ds = SQLiteHelper.ExecuteQuery("SELECT * FROM Users WHERE Name LIKE @p0", "%Ali%");
foreach (DataRow row in ds.Tables[0].Rows)
Console.WriteLine($"{row["Id"]}: {row["Name"]} - {row["Email"]}");
// 參數化查詢防注入,支援交易 (手動開啟 SQLiteTransaction)
using (var conn = new SQLiteConnection(SQLiteHelper.ConnectionString))
{
conn.Open();
using (var tran = conn.BeginTransaction())
{
try
{
new SQLiteCommand("INSERT INTO Users (Name) VALUES ('Bob')", conn, tran).ExecuteNonQuery();
new SQLiteCommand("INSERT INTO Users (Name) VALUES ('Carol')", conn, tran).ExecuteNonQuery();
tran.Commit();
}
catch { tran.Rollback(); throw; }
}
}
五、效能調優提示
- **WAL 模式**:
PRAGMA journal_mode=WAL; 大幅提升並發讀寫效能。
- **批次插入**:單一交易內執行大量
INSERT,或使用 SQLiteCommand.Prepare() + 參數陣列迴圈。
- **索引**:常用查詢欄位建立索引,
ANALYZE 更新統計資訊。
- **連線共用**:啟用
Pooling=true,避免頻繁開關連線。
六、官方資源