1.1. 簡介
SQLite 是一個進程內的庫,實現了自給自足的、無服務器的、零配置的、事務性的 SQL 數據庫引擎。它是一個零配置的數據庫,這意味着與其他數據庫一樣,你不需要在系統中配置。在 Golang 中使用SQLLite 也相當簡單,只需要安裝 SQLLite 的Golang 包即可使用;
Golang 就不多介紹了,能看到這個肯定對 Golang 有一定的瞭解。
倉庫地址:https://github.com/AndorLab/golang-sqllite
1.2. 目標
使用 SQLLite 通過構建一個社區用戶表,包含如下字段; 通過 SQLLite 的 API 實現對社區用戶表進行增刪改查。
序號 | 字段 | 類型 | 說明 |
---|---|---|---|
1 | uid | int64 | id |
2 | username | string | 用戶名 |
3 | city | string | 城市 |
4 | skills | string | 技能 |
5 | created | int64 | 創建時間 |
1.3. 目的
瞭解 SQLLite ,學習 Golang 操作 SQLLite, 鞏固 Golang 基礎知識。
1.4. Coding
1.4.1. 目錄結構
項目採用 Golang 傳統的平鋪式目錄
.
├── LICENSE
├── Makefile # 構建工具
├── README.md # README
├── db.go # 數據庫操作
├── error.go # 錯誤處理工具方法
├── fcc.db # sqllite 數據庫
├── go.mod # go modules
├── go.sum # go modules
├── main.go # 項目入口
├── server.go # 應用程序入口
└── userModel.go # 用戶模型
1.4.2. 封裝 error 函數
因爲在 go 中會有很多的 error 的判斷,爲了代碼精簡,我們特封裝一下 error; 下面的 interface{} 代表任何類型,類似 TypeScript 中的 any。
# error.go
func checkErr(data interface{}, err error) (interface{}, error) {
if err != nil {
log.Error(err)
return nil, err
}
return data, err
}
1.4.3. 安裝 SQLLite 庫及其他庫
使用 go modules 之後,將所需的包放在 import 中,使用 go mod tidy 命令後,go 會自動安裝程序使用到的包。
日誌相關的庫,主要用於在控制檯打印結果
# server.go
import (
"github.com/labstack/gommon/log"
)
SQLLite 包
# db.go
_ "github.com/mattn/go-sqlite3"
1.4.4. 申明 DB 全局變量
因爲在程序中,我們要通過數據庫來獲取數據,那麼存在一個全局的數據庫指針是很有必要的。
# main.go
var db = new(sql.DB)
1.4.5. 初始化數據庫
SQLLite 初始化數據庫非常簡單,只要指定數據庫驅動和數據庫文件就可以。爲了在程序的整個生命週期中操作數據庫,我們將 db 返回。
// openDB 打開數據庫
func openDB() *sql.DB {
//打開數據庫,如果不存在,則創建
db, err := sql.Open("sqlite3", "./fcc.db")
checkErr(db, err)
return db
}
創建好 db 後,需要創建表結構,執行如下數據庫操作命令即可完成用戶表的創建。
// initDB 初始化數據庫
func initDB() {
//創建表
sqlTable := `
CREATE TABLE IF NOT EXISTS userinfo(
uid INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(64) NULL,
city VARCHAR(64) NULL,
skills VARCHAR(128) NULL,
created BIGINT NULL
);
`
db.Exec(sqlTable)
}
1.4.6. 用戶模型構建及原子操作
構建現代程序,強調程序的健壯性,封裝就是比較重要的;用 MVC、 MVVM 的觀點,我們需要有一個 Model 來提供對象的原子操作。在這,我們將用戶抽象爲UserModel,對用戶的增刪改查封裝到 insert、dleete、update 和 query。
1.4.6.1. 用戶模型
// UserModel 用戶模型
type UserModel struct {
uid int64
username string
city string
skills string
created int64
}
對用戶的原子操作
1.4.6.2. 新增
// insert 新增
func (u UserModel) insert() (sql.Result, error) {
stmt, err := db.Prepare("insert into userinfo(username, city, skills, created) values(?,?,?,?)")
checkErr(stmt, err)
res, err := stmt.Exec(u.username, u.city, u.skills, time.Now().Unix())
checkErr(res, err)
return res, nil
}
1.4.6.3. 刪除
// delete 刪除
func (u UserModel) delete(id int64) int64 {
stmt, err := db.Prepare("delete from userinfo where uid=?")
checkErr(stmt, err)
res, err := stmt.Exec(id)
checkErr(res, err)
affect, err := res.RowsAffected()
checkErr(affect, err)
return affect
}
1.4.6.4. 修改
// update 更新用戶技能
func (u UserModel) update(id int) int64 {
stmt, err := db.Prepare("update userinfo set skills=? where uid=?")
checkErr(stmt, err)
res, err := stmt.Exec(u.skills, id)
checkErr(res, err)
affect, err := res.RowsAffected()
checkErr(affect, err)
return affect
}
1.4.6.5. 查詢
// query 查詢
func (u UserModel) query() ([]UserModel, error) {
rows, err := db.Query("select * from userinfo")
checkErr(rows, err)
var userList = []UserModel{}
for rows.Next() {
var user = UserModel{}
err = rows.Scan(&user.uid, &user.username, &user.city, &user.skills, &user.created)
checkErr(nil, err)
userList = append(userList, user)
}
rows.Close()
return userList, nil
}
1.4.7. 在應用中啓動並調用用戶模型的方法
在上面我們完成了對用戶模型及原子操作的封裝,那麼接下來就是通過應用程序將分裝的內容調用,傳入正確的參數進行調用。
我們在此封裝一個 startAPP 方法,在這個裏面我們調用封裝好的用戶操作的接口,實現功能。
因爲數據庫要在整個生命週期存在,當程序結束的時候,我們應該將數據庫鏈接釋放,所以我們用到了 go 的 defer 關鍵字
# server.go
db = openDB()
defer db.Close()
initDB()
調用用戶操作的增刪改查並打印結果, 對於不同的操作,我們應該有不同的數據,所以在程序中會有 user、和 updateUser 兩個對象
# server.go
user := UserModel{
username: "谷中仁",
city: `西安`,
skills: `TypeScript`,
}
// insert
result, err := user.insert()
id, err := result.LastInsertId()
checkErr(id, err)
log.Info("增:操作數據的id:", id)
// update
updateUser := UserModel{
skills: `golang`,
}
affectedRow := updateUser.updateSkills(1)
log.Info("改:影響的行數:", affectedRow)
// query
queryUser := UserModel{}
list, _ := queryUser.query()
log.Info("查:", list)
// delete
affect := queryUser.delete(1)
log.Info("刪:", affect)
// query
list, _ = queryUser.query()
log.Info("查:", list)
1.4.8. 運行結果展示
$ make run
go run *.go
{"time":"2019-08-31T14:21:48.941164+08:00","level":"INFO","prefix":"-","file":"server.go","line":"21","message":"增:操作數據的id:1"}
{"time":"2019-08-31T14:21:48.941842+08:00","level":"INFO","prefix":"-","file":"server.go","line":"27","message":"改:影響的行數:1"}
{"time":"2019-08-31T14:21:48.942034+08:00","level":"INFO","prefix":"-","file":"server.go","line":"31","message":"查:[{1 谷中仁 西安 golang 1567232508}]"}
{"time":"2019-08-31T14:21:48.942599+08:00","level":"INFO","prefix":"-","file":"server.go","line":"34","message":"刪:1"}
{"time":"2019-08-31T14:21:48.942696+08:00","level":"INFO","prefix":"-","file":"server.go","line":"38","message":"查:[]"}
1.5. 總結
SQLLite 對開發者非常友好,不用安裝在機器上,只要指定SQLLite的驅動和數據庫存儲文件即可對 SQLLite 數據庫進行操作;Golang 作爲比較流行的語言,對數據庫也非常友好,提供了基本的數據庫接口,
至於用戶需要什麼樣的數據庫,自己開發對應的數據庫驅動即可。當然在 GitHub 已經有很多開源愛好者開發了比較流行的數據庫的驅動可以直接拿來用。
SQLLite 使用的也是標準的 SQL 語法,可以讓不同的開發者快速入手。
爲什麼沒有用到 Golang 的 Web 框架?
因爲我們的側重點在 Golang 與 SQLLite,不在 API 實現上,最小化的實現目標,纔是我們學習知識最快速的途徑。
原文鏈接:https://chinese.freecodecamp.org/news/golang-with-sqllite-practice/