sqlite以其無需安裝和配置:直接使用數據庫文件,無需啟動獨立的數據庫服務進程。
單文件存儲:整個數據庫(包括表、索引、數據等)存儲在單個跨平臺文件中,便于遷移和備份。
在應對的小型應用軟件中.有著不可取代的地位.
sqlite使用 參考?10.1.SQLite-CSDN博客
10.2sql-CSDN博客?
go語言中使用sqlite
1. 推薦使用?go-sqlite3
?驅動,它基于 C 語言的 SQLite 庫實現:
go get github.com/mattn/go-sqlite3
2. 連接數據庫
使用 Go 標準庫?database/sql
?結合驅動進行操作:
package mainimport ("database/sql""fmt"_ "github.com/mattn/go-sqlite3" // 導入但不直接使用
)func main() {// 打開數據庫連接(如果文件不存在會自動創建)db, err := sql.Open("sqlite3", "./test.db")if err != nil {panic(err)}defer db.Close() // 程序結束時關閉連接// 驗證連接是否有效if err := db.Ping(); err != nil {panic(err)}fmt.Println("成功連接到SQLite數據庫")
}
3. 創建表
使用?Exec
?方法執行 SQL 語句:
// 創建表
func createTable(db *sql.DB) error {sqlStmt := `CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,age INTEGER);`_, err := db.Exec(sqlStmt)return err
}
4. 插入數據
支持普通插入和預處理語句(防止 SQL 注入):
// 普通插入
func insertData(db *sql.DB, name string, age int) error {sqlStmt := fmt.Sprintf("INSERT INTO users (name, age) VALUES ('%s', %d)", name, age)_, err := db.Exec(sqlStmt)return err
}// 預處理語句插入(推薦)
func insertDataWithPrepare(db *sql.DB, name string, age int) error {stmt, err := db.Prepare("INSERT INTO users (name, age) VALUES (?, ?)")if err != nil {return err}defer stmt.Close()_, err = stmt.Exec(name, age)return err
}
5. 查詢數據
- 單條記錄:使用?
QueryRow
- 多條記錄:使用?
Query
// 查詢單條記錄
func querySingleUser(db *sql.DB, id int) (string, int, error) {var name stringvar age interr := db.QueryRow("SELECT name, age FROM users WHERE id = ?", id).Scan(&name, &age)if err != nil {return "", 0, err}return name, age, nil
}// 查詢多條記錄
func queryAllUsers(db *sql.DB) ([]struct{ Name string; Age int }, error) {rows, err := db.Query("SELECT name, age FROM users")if err != nil {return nil, err}defer rows.Close()var users []struct{ Name string; Age int }for rows.Next() {var name stringvar age intif err := rows.Scan(&name, &age); err != nil {return nil, err}users = append(users, struct{ Name string; Age int }{name, age})}// 檢查迭代過程中是否有錯誤if err := rows.Err(); err != nil {return nil, err}return users, nil
}
6. 更新和刪除數據
// 更新數據
func updateUserAge(db *sql.DB, id, newAge int) error {stmt, err := db.Prepare("UPDATE users SET age = ? WHERE id = ?")if err != nil {return err}defer stmt.Close()_, err = stmt.Exec(newAge, id)return err
}// 刪除數據
func deleteUser(db *sql.DB, id int) error {stmt, err := db.Prepare("DELETE FROM users WHERE id = ?")if err != nil {return err}defer stmt.Close()_, err = stmt.Exec(id)return err
}
7. 事務處理
使用事務保證數據一致性:
func transferMoney(db *sql.DB, from, to int, amount float64) error {tx, err := db.Begin()if err != nil {return err}defer func() {if p := recover(); p != nil {tx.Rollback()panic(p) // 重新拋出異常} else if err != nil {tx.Rollback() // 發生錯誤時回滾} else {err = tx.Commit() // 提交事務}}()// 執行事務操作if _, err = tx.Exec("UPDATE accounts SET balance = balance - ? WHERE id = ?", amount, from); err != nil {return err}if _, err = tx.Exec("UPDATE accounts SET balance = balance + ? WHERE id = ?", amount, to); err != nil {return err}return nil
}
8. 啟用 WAL 模式
在連接字符串中添加?_journal_mode=WAL
?參數:
db, err := sql.Open("sqlite3", "./test.db?_journal_mode=WAL")
?SQLite 的 WAL(Write-Ahead Logging)模式是一種替代傳統回滾日志(ROLLBACK JOURNAL)的事務機制,它能顯著提升數據庫的并發性能和寫入吞吐量。
傳統模式(ROLLBACK JOURNAL)
- 寫操作流程:
- 將原始數據寫入臨時回滾日志(
.db-journal
)。 - 修改主數據庫文件。
- 事務提交后刪除回滾日志。
- 將原始數據寫入臨時回滾日志(
- 缺點:寫操作時需對整個數據庫加獨占鎖,導致讀寫互斥,并發性能差。
WAL 模式
- 寫操作流程:
- 將修改寫入獨立的 WAL 文件(
.db-wal
)。 - 事務提交時,只需要寫入一個 4 字節的提交標記到 WAL 文件末尾。
- 讀取操作直接從主數據庫和 WAL 文件合并后的狀態讀取。
- 將修改寫入獨立的 WAL 文件(
- 優點:讀寫操作可以并發進行(讀不阻塞寫,寫不阻塞讀)。
讀寫并發
- WAL 模式允許同時進行讀和寫操作,提升并發性能。
- 限制:同一時間只能有一個寫事務,但可以有多個并發讀事務。
?
9. 錯誤處理
// 檢查SQL執行結果
result, err := db.Exec("INSERT INTO ...")
if err != nil {log.Fatal(err)
}// 獲取插入ID
id, err := result.LastInsertId()
if err != nil {log.Fatal(err)
}// 獲取受影響行數
rowsAffected, err := result.RowsAffected()
if err != nil {log.Fatal(err)
}
完整示例
package mainimport ("database/sql""fmt""log"_ "github.com/mattn/go-sqlite3"
)func main() {// 連接數據庫db, err := sql.Open("sqlite3", "./test.db")if err != nil {log.Fatal(err)}defer db.Close()// 創建表if err := createTable(db); err != nil {log.Fatal(err)}// 插入數據if err := insertDataWithPrepare(db, "Alice", 30); err != nil {log.Fatal(err)}// 查詢數據users, err := queryAllUsers(db)if err != nil {log.Fatal(err)}fmt.Println("所有用戶:", users)// 更新數據if err := updateUserAge(db, 1, 31); err != nil {log.Fatal(err)}// 刪除數據if err := deleteUser(db, 1); err != nil {log.Fatal(err)}
}
注意事項
- 并發限制:SQLite 原生不支持多寫操作,高并發場景需考慮鎖機制或使用其他數據庫。
- 文件權限:確保數據庫文件所在目錄可讀寫。
- SQL 注入:始終使用預處理語句(
Prepare
?+?Exec
)避免 SQL 注入。