Xorm学习笔记
與你相識
博主介紹:
– 本人是普通大學生一枚,每天鉆研計算機技能,CSDN主要分享一些技術內容,因我常常去尋找資料,不經常能找到合適的,精品的,全面的內容,導致我花費了大量的時間,所以會將摸索的內容全面細致記錄下來。另外,我更多關于管理,生活的思考會在簡書中發布,如果你想了解我對生活有哪些反思,探索,以及對管理或為人處世經驗的總結,我也歡迎你來找我。
– 目前的學習專注于Go語言,輔學算法,前端領域。也會分享一些校內課程的學習,例如數據結構,計算機組成原理等等,如果你喜歡我的風格,請關注我,我們一起成長。
Table of Contents
- XORM學習筆記
- 對xorm的說明
- 安裝
- 創建orm引擎
- 定義表的結構體
- 統一前綴,后綴
- Column屬性
- 表結構操作
- 獲取數據庫表結構信息
- 表操作
- 同步數據庫結構
- 導入導出sql腳本
- 插入數據
- 使用xorm api來插入數據
- 使用SQL命令來插入數據
- 第1種方式
- 第2種方式
- 第3種方式
- 第4種方式
- 創建時間Created
- 查詢和統計數據
- ORM方式查詢和統計數據
- 更新數據
- update方法
- 樂觀鎖
- 更新時間
- 通過sql命令更新數據
- 第1種方式
- 第2種方式
- 第3種方式
- 第4種方式
- 刪除數據
- Delete方法
- 軟刪除 Deleted
- 通過sql語句刪除數據
- 第1種方式
- 第2種方式
- 第3種方式
- 第4種方式
- 事務
- 簡單事務使用
- 嵌套事務使用
- 數據導出
- 查詢結果集導出csv、tsv、xml、json、xlsx、yaml、html
- 多查詢集導出到單一文件
- 連接池
- 參考資料
XORM學習筆記
我直接看的官方說明文檔。
對xorm的說明
我現在所看的xorm庫,是基于原版xorm庫的定制增強版。
這是因為本定制版有第三方庫依賴,而就是為了維持原版xorm對第三方庫零依賴性,所以單獨開了一個定制增強版本的xorm庫。
相關核心功能和原版xorm一致并隨原版xorm更新。
安裝
go get -u github.com/xormplus/xorm創建orm引擎
xorm可以同時存在多個orm引擎,一個orm引擎稱為Engine,一個Engine一般只對應一個數據庫。
Engine通過調用xorm.NewEngine生成。
import (_ "github.com/go-sql-driver/mysql""github.com/xormplus/xorm" )var engine *xorm.Enginefunc main() {var err errorengine, err = xorm.NewEngine("mysql", "root:123@/test?charset=utf8") }engine可以通過engine.Close來手動關閉,但是一般情況下可以不用關閉,在程序退出的時候會自動關閉。
在engine創建完成之后可以設置一些選項:
日志是一個接口,通過設置日志,可以顯示SQL,警告以及錯誤等,默認的顯示級別為INFO。
- engine.ShowSQL(true),則會在控制臺打印出生成的SQL語句;
- engine.Logger().SetLevel(core.LOG_DEBUG),則會在控制臺打印調試及以上的信息;
如果希望將信息不僅打印到控制臺,而是保存為文件,那么可以通過類似如下的代碼實現,NewSimpleLogger(w io.Writer)接收一個io.Writer接口來將數據寫入到對應的設施中。
f, err := os.Create("sql.log") if err != nil {println(err.Error())return } engine.SetLogger(xorm.NewSimpleLogger(f))定義表的結構體
統一前綴,后綴
可以通過一種方式在表的字段前加上統一的前綴,后綴或緩存映射,但是表字段不會改變。
// 統一前綴 tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, "prefix_") engine.SetTableMapper(tbMapper) // 統一后綴 ore.NewSufffixMapper(core.SnakeMapper{}, "suffix")Column屬性
可以在列中對Column的一些屬性進行定義
type User struct {Id int64Name string `xorm:"varchar(25) notnull unique 'usr_name'"` }還有很多其它的內容,參考官方操作手冊。
表結構操作
獲取數據庫表結構信息
- DBMetas()
xorm支持獲取表結構信息,通過調用engine.DBMetas()可以獲取到數據庫中所有的表,字段,索引的信息。
表操作
- CreateTables()
創建表使用engine.CreateTables(),參數為一個或多個空的對應Struct的指針。同時可用的方法有Charset()和StoreEngine(),如果對應的數據庫支持,這兩個方法可以在創建表時指定表的字符編碼和使用的引擎。Charset()和StoreEngine()當前僅支持Mysql數據庫。
- IsTableEmpty()
判斷表是否為空,參數和CreateTables相同
- IsTableExist()
判斷表是否存在
- DropTables()
刪除表使用engine.DropTables(),參數為一個或多個空的對應Struct的指針或者表的名字。如果為string傳入,則只刪除對應的表,如果傳入的為Struct,則刪除表的同時還會刪除對應的索引。
同步數據庫結構
同步能夠部分智能的根據結構體的變動檢測表結構的變動,并自動同步。目前有兩個實現:
Sync
Sync將進行如下的同步操作:
- 自動檢測和創建表,這個檢測是根據表的名字
- 自動檢測和新增表中的字段,這個檢測是根據字段名
- 自動檢測和創建索引和唯一索引,這個檢測是根據索引的一個或多個字段名,而不根據索引名稱
Sync2
對sync進行了改進,目前推薦使用。
下面的警告信息需要將engine.ShowWarn設置為true才會實現
- 自動檢測和創建表,這個檢測是根據表的名字
- 自動檢測和新增表中的字段,這個檢測是根據字段名,同時對表中多余的字段給出警告信息
- 自動檢測,創建和刪除索引和唯一索引,這個檢測是根據索引的一個或多個字段名,而不根據索引名稱。因此這里需要注意,如果在一個有大量數據的表中引入新的索引,數據庫可能需要一定的時間來建立索引。
- 自動轉換varchar字段類型到text字段類型,自動警告其它字段類型在模型和數據庫之間不一致的情況。
- 自動警告字段的默認值,是否為空信息在模型和數據庫之間不匹配的情況
導入導出sql腳本
導入:
如果你需要將保存在文件或者其它存儲設施中的SQL腳本執行,那么可以調用
engine.Import(r io.Reader)和
engine.ImportFile(fpath string)導出:
如果需要在程序中Dump數據庫的結構和數據可以調用
engine.DumpAll(w io.Writer)和
engine.DumpAllFile(fpath string)DumpAll方法接收一個io.Writer接口來保存Dump出的數據庫結構和數據的SQL語句,這個方法導出的SQL語句并不能通用。只針對當前engine所對應的數據庫支持的SQL。
插入數據
使用xorm api來插入數據
使用Insert或InsertOne來插入數據
user := new(User) user.Name = "myname" affected, err := engine.Insert(user) // INSERT INTO user (name) values (?)- 批量插入會自動生成Insert into table values (),(),()的語句,因此各個數據庫對SQL語句有長度限制,因此這樣的語句有一個最大的記錄數,根據經驗測算在150條左右。大于150條后,生成的sql語句將太長可能導致執行失敗。因此在插入大量數據時,目前需要自行分割成每150條插入一次。
使用SQL命令來插入數據
第1種方式
sql ="insert into config(key,value) values (?, ?)" res, err := engine.Exec(sql, "OSCHINA", "OSCHINA")第2種方式
sql_2 := "insert into config(key,value) values (?, ?)" affected, err := engine.Sql(sql_4, "OSCHINA", "OSCHINA").Execute()第3種方式
//SqlMap中key為 "sql_i_1" 配置的Sql語句為:insert into config(key,value) values (?, ?) sql_i_1 := "sql_i_1" affected, err := engine.SqlMapClient(sql_i_1, "config_1", "1").Execute()//SqlMap中key為 "sql_i_2" 配置的Sql語句為:insert into config(key,value) values (?key, ?value) sql_i_2 := "sql_i_2" paramMap_i := map[string]interface{}{"key": "config_2", "value": "2"} affected, err := engine.SqlMapClient(sql_i_2, ¶mMap_i).Execute()第4種方式
sql_i_3 := "insert.example.stpl" paramMap_i_t := map[string]interface{}{"key": "config_3", "value": "3"} affected, err := engine.SqlTemplateClient(sql_i_3, ¶mMap_i_t).Execute()創建時間Created
我感覺這個特性很有意思。它可以讓你在數據插入到數據庫的時候自動將對應的字段設置為當前的時間,需要在xorm標記中使用created標記。 字段可以是time.Time、int、int64、int32等int類型。
只需要在后面加上xorm的映射即可,當添加記錄的時候,created標記的字段就會被自動更新為當前時間。
type User struct {Id int64Name stringCreatedAt time.Time `xorm:"created"` }查詢和統計數據
ORM方式查詢和統計數據
ORM所有的查詢條件不區分調用順序,但必須在調用Get,Find,Count,Iterate,Rows之前調用。
查詢單條語句用Get,查詢多條語句用Find
Rows和Iterate方法可以把查詢的結果逐條的展示出來,Rows更加靈活。
更新數據
update方法
使用如下的方式來更新
user := new(User) user.Name = "myname" affected, err := engine.Id(id).Update(user)樂觀鎖
可以使用如下方式添加樂觀鎖,在insert的時候,version標記的字段將會被設置為1。
type User struct { Id int64 Name string Version int xorm:"version" }在update的時候,update結構體中的內容必須包含原version的值
var user User engine.Id(1).Get(&user) // SELECT * FROM user WHERE id = ? engine.Id(1).Update(&user) // UPDATE user SET ..., version = version + 1 WHERE id = ? AND version = ?更新時間
可以通過updated標記,當調用Insert(), InsertOne(), Update()方法的時候,會自動的將對應自動設置為當前時間,對應的字段可以為time.Time或者自定義的time.Time或者int,int64等int類型。
type User struct {Id int64Name stringUpdatedAt time.Time `xorm:"updated"` }通過sql命令更新數據
第1種方式
sql ="update user set age = ? where name = ?" res, err := engine.Exec(sql, 1, "xorm")第2種方式
sql_2 := "update user set age = ? where name = ?" affected, err := engine.Sql(sql_2, 1, "xorm").Execute()第3種方式
//SqlMap中key為 "sql_i_1" 配置的Sql語句為:update user set age = ? where name = ? sql_i_1 := "sql_i_1" affected, err := engine.SqlMapClient(sql_i_1, 1, "xorm").Execute()//SqlMap中key為 "sql_i_2" 配置的Sql語句為:update user set age = ?age where name = ?name sql_i_2 := "sql_i_2" paramMap_i := map[string]interface{}{"age": 1, "name": "xorm"} affected, err := engine.SqlMapClient(sql_i_2, ¶mMap_i).Execute()第4種方式
sql_i_3 := "insert.example.stpl" paramMap_i_t := map[string]interface{}{"age": 1, "name": "xorm"} affected, err := engine.SqlTemplateClient(sql_i_3, ¶mMap_i_t).Execute()刪除數據
Delete方法
第一個參數為刪除的記錄數,第二個為執行錯誤
user := new(User) affected, err := engine.Id(id).Delete(user)注意:當刪除時,如果user中包含有bool,float64或者float32類型,有可能會使刪除失敗。具體請查看 FAQ
軟刪除 Deleted
在我以前的使用中,軟刪除都是要自己去做的,但是XORM通過標記給我們做好了。
type User struct {Id int64Name stringDeletedAt time.Time `xorm:"deleted"`// 通過Cols來指定只更新某列affected, err := engine.Id(id).Cols("age").Update(&user) }通過sql語句刪除數據
第1種方式
sql ="delete from user where id = ?" res, err := engine.Exec(sql, 1)第2種方式
sql_2 := "delete from user where id = ?" affected, err := engine.Sql(sql_2, 1).Execute()第3種方式
//SqlMap中key為 "sql_i_1" 配置的Sql語句為:delete from user where id = ? sql_i_1 := "sql_i_1" affected, err := engine.SqlMapClient(sql_i_1, 1).Execute()//SqlMap中key為 "sql_i_2" 配置的Sql語句為:delete from user where id = ?id sql_i_2 := "sql_i_2" paramMap_i := map[string]interface{}{"id": 1} affected, err := engine.SqlMapClient(sql_i_2, ¶mMap_i).Execute()第4種方式
sql_i_3 := "insert.example.stpl" paramMap_i_t := map[string]interface{}{"id": 1} affected, err := engine.SqlTemplateClient(sql_i_3, ¶mMap_i_t).Execute()事務
簡單事務使用
session := engine.NewSession() defer session.Close() // add Begin() before any action err := session.Begin() user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} _, err = session.Insert(&user1) if err != nil {session.Rollback()return } user2 := Userinfo{Username: "yyy"} _, err = session.Where("id = ?", 2).Update(&user2) if err != nil {session.Rollback()return }_, err = session.Exec("delete from userinfo where username = ?", user2.Username) if err != nil {session.Rollback()return }// add Commit() after all actions err = session.Commit() if err != nil {return }嵌套事務使用
在通常情況下,簡單事務夠我們使用了。 它與簡單事務的不同在于,簡單事務在同一個session下工作,而嵌套事物則會返回Transaction實例,后續操作則在同一個實例下操作。
session := engine.NewSession() defer session.Close() // add BeginTrans() before any action tx, err := session.BeginTrans() if err != nil {return }user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} _, err = tx.Session().Insert(&user1) if err != nil {tx.Rollback()return }user2 := Userinfo{Username: "yyy"} _, err = tx.Session().Where("id = ?", 2).Update(&user2) if err != nil {tx.RollbackTrans()return }_, err = tx.Session().Exec("delete from userinfo where username = ?", user2.Username) if err != nil {tx.RollbackTrans()return }_, err = tx.Session().SqlMapClient("delete.userinfo", user2.Username).Execute() if err != nil {tx.RollbackTrans()return }// add CommitTrans() after all actions err = tx.CommitTrans() if err != nil {...return }數據導出
查詢結果集導出csv、tsv、xml、json、xlsx、yaml、html
xorm查詢結果集支持導出csv、tsv、xml、json、xlsx、yaml、html七種文件格式
以導出xlsx文件格式為例,代碼如下
err := engine.Sql("select * from category").Query().SaveAsXLSX("1.xlsx", []string{"id", "name", "counts", "orders", "createtime", "pid", "lastupdatetime", "status"}, 0777)if err != nil {t.Fatal(err) }- SaveAsCSV(filename string, headers []string, perm os.FileMode)
導出CSV文件,filename為完整路徑,headers為每列的列名,需要結果集中有該字段,此處[]string是為了確定列的順序,perm為文件權限位
- SaveAsTSV(filename string, headers []string, perm os.FileMode)
導出TSV文件,filename為完整路徑,headers為每列的列名,需要結果集中有該字段,此處[]string是為了確定列的順序,perm為文件權限位
- SaveAsHTML(filename string, headers []string, perm os.FileMode)
導出HTML文件,filename為完整路徑,headers為每列的列名,需要結果集中有該字段,此處[]string是為了確定列的順序,perm為文件權限位
- SaveAsXML(filename string, headers []string, perm os.FileMode)
導出XML文件,filename為完整路徑,headers為每列的列名,需要結果集中有該字段,此處[]string是為了確定列的順序,perm為文件權限位
- SaveAsXMLWithTagNamePrefixIndent(tagName string, prifix string, indent string, filename string, headers []string, perm os.FileMode)
導出指定格式化的XML文件,filename為完整路徑,headers為每列的列名,需要結果集中有該字段,此處[]string是為了確定列的順序,perm為文件權限位
- SaveAsYAML(filename string, headers []string, perm os.FileMode)
導出YAML文件,filename為完整路徑,headers為每列的列名,需要結果集中有該字段,此處[]string是為了確定列的順序,perm為文件權限位
- SaveAsJSON(filename string, headers []string, perm os.FileMode)
導出JSON文件,filename為完整路徑,headers為每列的列名,需要結果集中有該字段,此處[]string是為了確定列的順序,perm為文件權限位
- SaveAsXLSX(filename string, headers []string, perm os.FileMode)
導出XLSX文件,filename為完整路徑,headers為每列的列名,需要結果集中有該字段,此處[]string是為了確定列的順序,perm為文件權限位
多查詢集導出到單一文件
樣例代碼:
_, results, err := engine.Sqls(map[string]string{"category": "select * from category", "category-16-17": "select * from category where id in (16,17)"}).Execute()if err != nil {t.Fatal(err) }databook, err := xorm.NewDatabookWithData(map[string]string{"category": "category","category-16-17": "category-16-17"},results,true,map[string][]string{"category": []string{"id", "name", "counts", "orders", "createtime", "pid", "lastupdatetime", "status"},"category-16-17": []string{"id", "name", "counts", "orders", "createtime", "pid", "lastupdatetime", "status"}})if err != nil {t.Fatal(err) }err = databook.SaveAsXLSX("c:/2.xlsx", 0777) if err != nil {t.Fatal(err) } err = databook.SaveAsHTML("c:/2.html", 0777) if err != nil {t.Fatal(err) } err = databook.SaveAsJSON("c:/2.json", 0777) if err != nil {t.Fatal(err) } err = databook.SaveAsXML("c:/2.xml", 0777) if err != nil {t.Fatal(err) } err = databook.SaveAsYAML("c:/2.yaml", 0777) if err != nil {t.Fatal(err) }連接池
engine內部支持連接池接口和對應的函數。
- 如果需要設置連接池的空閑數大小,可以使用engine.SetMaxIdleConns()來實現。
- 如果需要設置最大打開連接數,則可以使用engine.SetMaxOpenConns()來實現。
參考資料
- xorm操作指南(官方)
歡迎評論區討論,或指出問題。 如果覺得寫的不錯,歡迎點贊,轉發,收藏。
總結
- 上一篇: cad字体安装_设计师,你的CAD图纸中
- 下一篇: android 根目录缓存,Androi