這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
注意事項
本部落格隸屬於 xorm - 課時 1:常見用法指導 請注意配套使用。
本博文為 xorm - Go 語言 ORM 的配套部落格,旨在通過文字結合程式碼範例對該庫的使用方法和案例進行講解,便於各位同學更好地使用和深入瞭解。
庫簡介
xorm 是一款針對 Go 語言的 ORM 第三方庫,特點是提供簡單但豐富實用的 API 來完成對資料庫的各類操作。該庫支援包括 MySQL、PostgreSQL、SQLite3 和 MsSQL 在內的主流資料庫,其在支援鏈式操作的基礎上,還允許結合 SQL 陳述式進行混合處理。另外,支援 session 事務和復原以及樂觀鎖也是使得該庫逐漸流行的原因之一。
下載安裝
您可以通過以下兩種方式下載安裝 xorm:
gopm get github.com/go-xorm/xorm
或
go get github.com/go-xorm/xorm
API 文檔
請移步 Go Walker。
基本使用方法
範例程式碼
定義模型
在使用 Go 語言的 ORM 之前,都需要對模型進行定義。對於 Go 語言而言,通過定義一個結構體(struct)和該結構體的欄位的類型與 tag 來完成對模型的定義。例如,在本課時的例子中,我們就通過以下代碼來定義一個銀行賬戶的模型:
type Account struct { Id int64 Name string `xorm:"unique"` Balance float64 Version int `xorm:"version"` // 樂觀鎖}
由於關係型資料庫涉及到主鍵問題,為了方便使用者的使用,凡是類型為 int64
且欄位名為 Id
且沒有定義任何 tag 的欄位,都會自動被認為是主鍵。如果您想要採用其它名稱為主鍵,則可以在 tag 中設定 pk
來告知 xorm。
欄位 Name
的 tag 使用了 unique
則表示該欄位記錄的值在整個資料表中是唯一的,不能夠出現重複的使用者名稱。
最後一行的樂觀鎖暫不深入,後文會講到。
在定義模型時需要注意的是所有欄位的首字母必須是大寫的(Go 語言的匯出規則),否則 ORM 是無法通過反射擷取到欄位的名稱和類型,可能會引發 panic。
由於例子比較簡單,並不能夠列舉出所有 xorm 支援的 tag 定義,完整的列表可以查看 這裡。
建立 ORM 引擎
在完成模型定義之後,我們就需要建立 ORM 的引擎了。在建立 ORM 引擎這個步驟時,您需要確定您所使用的資料庫驅動以及相關的連結資訊(資料庫 HOST、使用者、密碼等)。本例採用的是 SQLite3,所以只需要指定資料庫檔案所在的路徑就可以了:
x, err = xorm.NewEngine("sqlite3", "./bank.db")
Go 語言要求所使用的資料庫驅動必須註冊之後才能使用,因此所有的驅動庫都會在 init 函數中對自身進行註冊,以便我們在使用時候不會出現錯誤。同樣地,使用 ORM 也是需要對我們所使用的資料庫驅動進行註冊,那麼如何註冊呢?
由於資料庫驅動的種類較多,一般每個 ORM 都只會對一種資料庫選擇一個驅動進行支援,所以在註冊驅動之前,需要確認一下您所使用的 ORM 是否支援您所選的驅動。比如 xorm 就支援多達 5 種資料庫驅動。
註冊資料庫驅動的方法如下:
import ( _ "github.com/mattn/go-sqlite3")
很多同學看到匯入路徑前面的 _
底線表示不解,這是沒有學習好無聞出品的 《Go編程基礎》 的惡果。在匯入路徑前加入底線表示只執行該庫的 init 函數而不對其它匯出對象進行真正地匯入。因為 Go 語言的資料庫驅動都會在 init 函數中註冊自己,所以我們只需要進行上述操作即可;否則的話,Go 語言的編譯器會提示匯入了包卻沒有使用的錯誤。
自動同步表結構
xorm 有一個非常贊的功能,就是支援自動增量同步處理資料表結構。什麼意思呢?就是在您完成資料庫的建立之後,ORM 會自動根據所定義的模型來自動建立資料表,這就是為什麼我們需要使用 tag 來對欄位進行一些特別的指定(例如:unique)。所謂增量同步處理,就是指只會對新增的欄位或 tag 定義進行同步,包括新定義的模型、欄位和 tag 規則;如果您刪除或修改了某個欄位,出於安全考慮,已經建立的列(column)是不會被刪除或修改的,而是直接忽略或建立修改後的列。
通過下面的方法,就能夠調用 xorm 提供的自動同步資料表結構的功能:
err = x.Sync(new(Account))
方法 Sync
需要傳入所有您將會用到的模型,本例中只有 Account
。之所以使用 new()
方法進行一次建立對象是因為 ORM 的解析結構體的工作都是通過反射完成的,只有傳遞一個執行個體對象才能夠讓 ORM 擷取到相應的欄位和 tag。
增、刪、改操作
首先,我們來看看如何使用 xorm 實現最基本的增、刪、改操作。
新增記錄
插入一條新的記錄,該記錄必須是未存在的,否則會返回錯誤:
_, err := x.Insert(&Account{Name: name, Balance: balance})
刪除記錄
刪除一條記錄:
_, err := x.Delete(&Account{Id: id})
方法 Delete
接受參數後,會自動根據傳進去的值進行尋找,然後刪除。比如此處,我們指定了 Account
的 ID 欄位,那麼就會刪除 ID 欄位值與我們所賦值相同的記錄;如果您只對 Name 欄位賦值,那麼 xorm 就會去尋找 Name 欄位值匹配的記錄。如果多個欄位同時賦值,則是多個條件同時滿足的記錄才會被刪除。
刪除操作針對的對象沒有限制,凡是按照條件尋找到的,都會被刪除(單個與大量刪除)。
擷取與修改記錄
根據 xorm 的要求,想要更新一條記錄則該記錄必須是已存在的,所以我們需要先擷取記錄的相應資訊,然後做修改,最後進行更新:
a := &Account{}has, err := x.Id(id).Get(a)
方法 Get
只會返回單個記錄,與刪除操作類似的,任何對於變數 a 的賦值就會變成尋找條件。但 xorm 的靈活之處在於,您還可以通過鏈式操作方便的達到同樣的需求。正如本例中直接使用 Id
方法來擷取指定 ID 的記錄一樣。
該方法會返回兩個值,第一個為 bool 類型,表示是否尋找到記錄;第二個為 error 類型,表示是否發生其它錯誤。
在擷取到記錄之後,我們就需要進行一些修改,然後更新到資料庫:
a.Balance += deposit// 對已有記錄進行更新_, err = x.Update(a)
方法 Update
接受的第一個參數必須是指標地址,指向需要更新的內容。此外,它還允許接收第二個參數,與之前在刪除和擷取操作中提到的條件查詢作用相同,如果您傳入了第二個參數,則會根據參數進行條件式篩選,然後更新相應的欄位。
批量擷取資訊
除了對單個記錄進行擷取之外,為了能夠更好的查看內容,有時我們會需要一次性取出多條記錄,並進行一定的排序。
因此,與擷取單個記錄的 Get
方法相對應的是擷取所有合格記錄的 Find
方法:
err = x.Desc("balance").Find(&as)
在這裡,我們還調用了 Desc
方法對記錄按照存款數額將賬戶從大到小排序。
方法 Find
接受的第一個參數必須是某個類型的 slice 的指標地址,本例中使用的是元素類型為 Account
類型的 slice 的指標地址;它的第二個參數也是條件參數,作用前文已經詳細描述。
樂觀鎖
樂觀鎖是 xorm 提供的一個比較實用的功能,通過在 tag 中指定 version
來開啟它。開啟之後,每次對記錄進行更新的時候,該欄位的值就會自動遞增 1。如此一來,您就可以判斷是否有其它地方同時修改了該記錄,如果是,則應當重新操作,否則會出現錯誤的資料(同時對一個帳號進行取款操作卻只扣了一次的數額)。
小結
本課時只是針對 xorm 的講解的第一課時,在代碼實現上追求基礎、直觀,並未涉及到非常多的內容,以免讓新手顯得迷茫。所以,本例中的代碼實際上是存在一些缺陷的,比如說在轉賬就應該使用事務以便發生錯誤時進行復原,以免轉賬失敗時轉賬雙方都沒有迴歸到原有的數額。