golang 之xorm


xorm

  xorm是一個簡單而強大的ORM庫。

  安裝

go get -u github.com/go-xorm/xorm

  驅動支持

Mysql: github.com/go-sql-driver/mysql
MyMysql: github.com/ziutek/mymysql
Postgres: github.com/lib/pq
Tidb: github.com/pingcap/tidb
SQLite: github.com/mattn/go-sqlite3
MsSql: github.com/denisenkom/go-mssqldb
MsSql: github.com/lunny/godbc
Oracle: github.com/mattn/go-oci8 (試驗性支持)

創建orm引擎

  一個xorm可同時存在orm引擎,一個Orm引擎稱為Engine,一個Engine一般只對應一個數據庫。Engine通過調用xorm.NewEngine生成,如:

package main

import (
	"github.com/go-xorm/xorm"
	_ "github.com/go-sql-driver/mysql"

)

func main()  {
	engine, err := xorm.NewEngine("mysql", "root:passwd@tcp(127.0.0.1:3306)/dabase_name?timeout=3s&parseTime=true&loc=Local&charset=utf8")
	if err !=nil{
		return
	}
	engine.Ping()  // 可以判斷是否能連接
	
	defer engine.Close()  // 退出后關閉
}

定義表結構體

  表名映射一般有三種方式,且都按優先級高低

  • 表名的優先級順序如下:

    • engine.Table() 指定的臨時表名優先級最高
    • TableName() string 其次
    • Mapper 自動映射的表名優先級最后
  • 字段名的優先級順序如下:

    • 結構體tag指定的字段名優先級較高
    • Mapper 自動映射的表名優先級較低  

  Column屬性定義,首先定義一個結構體如

type User struct {
    Id      int64
    Name string  `xorm:"varchar(25) notnull unique 'usr_name'"`
    Balance float64
    Version int `xorm:"version"` // 樂觀鎖
}

  具體tag詳情如下。且字段名根據不同數據庫區分大小寫

Tag 說明
name 當前field對應的字段的名稱,可選,如不寫,則自動根據field名字和轉換規則命名,如與其它關鍵字沖突,請使用單引號括起來。
pk 是否是Primary Key,如果在一個struct中有多個字段都使用了此標記,則這多個字段構成了復合主鍵,單主鍵當前支持int32,int,int64,uint32,uint,uint64,string這7種Go的數據類型,復合主鍵支持這7種Go的數據類型的組合。
當前支持30多種字段類型,詳情參見本文最后一個表格 字段類型
autoincr 是否是自增
[not ]null 或 notnull 是否可以為空
unique或unique(uniquename) 是否是唯一,如不加括號則該字段不允許重復;如加上括號,則括號中為聯合唯一索引的名字,此時如果有另外一個或多個字段和本unique的uniquename相同,則這些uniquename相同的字段組成聯合唯一索引
index或index(indexname) 是否是索引,如不加括號則該字段自身為索引,如加上括號,則括號中為聯合索引的名字,此時如果有另外一個或多個字段和本index的indexname相同,則這些indexname相同的字段組成聯合索引
extends 應用於一個匿名成員結構體或者非匿名成員結構體之上,表示此結構體的所有成員也映射到數據庫中,extends可加載無限級
- 這個Field將不進行字段映射
-> 這個Field將只寫入到數據庫而不從數據庫讀取
<- 這個Field將只從數據庫讀取,而不寫入到數據庫
created 這個Field將在Insert時自動賦值為當前時間
updated 這個Field將在Insert或Update時自動賦值為當前時間
deleted 這個Field將在Delete時設置為當前時間,並且當前記錄不刪除
version 這個Field將會在insert時默認為1,每次更新自動加1
default 0或default(0) 設置默認值,緊跟的內容如果是Varchar等需要加上單引號
json 表示內容將先轉成Json格式,然后存儲到數據庫中,數據庫中的字段類型可以為Text或者二進制

  需要注意的幾點

  • 如果field名稱為ID,且類型為int64,並且 沒有定義tag,則會被xorm視為主鍵,且擁有自增屬性。如果要用其它名字為主鍵,需對應tag加上 xorm:"pk"
  • string類型默認為varchar(255)
  • 支持type MyString string 等自定義的field。支持Slice, Map,等field成員。這些成員默認存儲為Text類型。並且擁有Json格式來序列化和反序列化。
  • 實現Conversion接口的類型或者結構體,將根據接口的轉換方式在類型和數據庫記錄之間進行相互轉換。
    type Conversion interface {
        FromDB([]byte) error
        ToDB() ([]byte, error)
    }
    

     

表結構常用操作

  獲取數據庫信息

  • DBMetas(): xorm支持獲取表結構信息。通過調用engine.DBMetas()獲取表,字段,索引信息
  • TableInfo(): 根據傳入的結構體指針及對應的Tag,提取出模型對應的表結構信息。

  表操作

  • CreateTables(): 創建表engine.CreateTables() 參數為一個或多個空的對應Struct的指針。可用方法有Charset()和StoreEngine()。
  • IsTableEmpty(): 判斷是否為空。參數和CreateTables()相同。
  • IsTableExist():判斷是否存在
  • DropTables(): 刪除表engine.DropTables().參數為一個或多個空的對應Struct的指針或者表的名字。如果為string傳入,則只刪除對應的表,如果傳入的為Struct,則刪除表的同時還會刪除對應的索引。

  創建索引和唯一索引

  • CreateIndexes: 根據struct中的Tag來創建索引
  • CreateUniques: 根據struct中的tag來創建唯一索引

  同步數據庫結構到 mysql中

  • Sync
    • 自動檢測和創建表,這個檢測是根據表的名字
    • 自動檢測和新增表中的字段,這個檢測是根據字段名
    • 自動檢測和創建索引和唯一索引,這個檢測是根據索引的一個或多個字段名,而不根據索引名稱
      err := engine.Sync(new(User), new(Group))
      // 其中User ,Group為要創建的兩個表對應的struct
    Sync2, 對Sync進行改進,推薦使用Sync2
    • 自動檢測和創建表,這個檢測是根據表的名字
    • 自動檢測和新增表中的字段,這個檢測是根據字段名,同時對表中多余的字段給出警告信息
    • 自動檢測,創建和刪除索引和唯一索引,這個檢測是根據索引的一個或多個字段名,而不根據索引名稱。因此這里需要注意,如果在一個有大量數據的表中引入新的索引,數據庫可能需要一定的時間來建立索引。
    • 自動轉換varchar字段類型到text字段類型,自動警告其它字段類型在模型和數據庫之間不一致的情況。
    • 自動警告字段的默認值,是否為空信息在模型和數據庫之間不匹配的情況

   以上信息需要將engine.ShowWarn設置為true才會顯示。調用方法

err := engine.Sync2(new(User), new(Group))

  導入導出SQL腳本

  dump

engine.DumpAll(w io.Writer)
或
engine.DumpAllFile(fpath string)

  Import

engine.Import(r io.Reader)
或者
engine.ImportFile(fpath string)

插入數據操作(表結構參照上面User表)

  ORM插入一條數據

user := new(User)
user.Name = "myname"
affected, err := engine.Insert(user)
// INSERT INTO user (name) values (?)

   插入同一個表的多條數據

users := make([]User, 1)
users[0].Name = "name0"
users[0].ID = "0"
...
affected, err := engine.Insert(&users)

  指針Slice插入多條記錄

users := make([]*User, 1)
users[0] = new(User)
users[0].Name = "name0"
users[0].ID = "0"
...
affected, err := engine.Insert(&users)

  不同表的一條記錄

user := new(User)
user.Name = "myname"
question := new(Question)
question.Content = "whywhywhwy?"
affected, err := engine.Insert(user, question)

  不同表的多條記錄

users := make([]User, 1)
users[0].Name = "name0"
...
questions := make([]Question, 1)
questions[0].Content = "whywhywhwy?"
affected, err := engine.Insert(&users, &questions)

  使用SQL插入數據

sql ="insert into config(key,value) values (?, ?)"
res, err := engine.Exec(sql, "OSCHINA", "OSCHINA") 
或者
sql_2 := "insert into config(key,value) values (?, ?)"
affected, err := engine.Sql(sql_4, "OSCHINA", "OSCHINA").Execute()
或者
//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()
或者
sql_i_3 := "insert.example.stpl"
paramMap_i_t := map[string]interface{}{"key": "config_3", "value": "3"}
affected, err := engine.SqlTemplateClient(sql_i_3, &paramMap_i_t).Execute()

查詢操作

  ORM常用查詢

  注意下面出現的 & +表結構體

  設置別名

engine.Alias("o").Where("o.name = ?", name).Get(&order)

  條件查找

engine.Where(...).And(...).Get(&order)

  某個字段排序

// 正序
engine.Asc("id").Find(&orders)
//倒序
engine.Asc("id").Desc("time").Find(&orders)

  主鍵查找

var user User
engine.Id(1).Get(&user)
// SELECT * FROM user Where id = 1

// 或者復合主鍵
engine.Id(core.PK{1, "name"}).Get(&user)
// SELECT * FROM user Where id =1 AND name= 'name'

  select, in, cols

engine.Select("a.*, (select name from b limit 1) as name").Find(&beans)
engine.Select("a.*, (select name from b limit 1) as name").Get(&bean)


// in
engine.In("cloumn", 1, 2, 3).Find()
engine.In("column", []int{1, 2, 3}).Find()

// cols
engine.Cols("age", "name").Get(&usr)
// SELECT age, name FROM user limit 1
engine.Cols("age", "name").Find(&users)
// SELECT age, name FROM user
engine.Cols("age", "name").Update(&user)
// UPDATE user SET age=? AND name=?

  GET方法,查詢到的數據會賦給結構體

has, err := engine.Get(&user)
// SELECT * FROM user LIMIT 1
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
var name string
has, err := engine.Where("id = ?", id).Cols("name").Get(&name)
// SELECT name FROM user WHERE id = ?
var id int64
has, err := engine.Where("name = ?", name).Cols("id").Get(&id)
// SELECT id FROM user WHERE name = ?
var valuesMap = make(map[string]string)
has, err := engine.Where("id = ?", id).Get(&valuesMap)
// SELECT * FROM user WHERE id = ?
var valuesSlice = make([]interface{}, len(cols))
has, err := engine.Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
// SELECT col1, col2, col3 FROM user WHERE id = ?
或者
user := new(User)
has, err := engine.Where("name=?", "xlw").Get(user)

 子查詢

var student []Student
err = db.Table("student").Select("id ,name").Where("id in (?)", db.Table("studentinfo").Select("id").Where("status = ?", 2).QueryExpr()).Find(&student)
//SELECT id ,name FROM `student` WHERE (id in (SELECT id FROM `studentinfo` WHERE (status = 2)))

  SQL操作返回格式json or xml

var users []User
results,err := engine.Where("id=?", 6).Search(&users).Xml() //返回查詢結果的xml字符串
results,err := engine.Where("id=?", 6).Search(&users).Json() //返回查詢結果的json字符串

更新操作

  update方法

user := new(User)
user.Name = "myname"
affected, err := engine.Id(id).Update(user)

  指定更新值

affected, err := engine.Id(id).Cols("age").Update(&user)
// 或
affected, err := engine.Table(new(User)).Id(id).Update(map[string]interface{}{"age":0})

  更新時間,可以在字段名后添加 update如下

type User struct {
    Id int64
    Name string
    UpdatedAt time.Time `xorm:"updated"`
}

刪除操作

  delete方法

user := new(User)
affected, err := engine.Id(id).Delete(user)

//Delete的返回值第一個參數為刪除的記錄數,第二個參數為錯誤。

  xorm還提供了軟刪除,如下設置

type User struct {
    Id int64
    Name string
    DeletedAt time.Time `xorm:"deleted"`
}

  如果設置軟刪除,那么永久刪除或者獲取使用Unscoped

var user User
engine.Id(1).Unscoped().Get(&user)
// 此時將可以獲得記錄
engine.Id(1).Unscoped().Delete(&user)
// 此時將可以真正的刪除記錄

創建數據庫組

  xorm提供了可以連接多個數據庫。如下

package main

import (
	"github.com/go-xorm/xorm"
	_ "github.com/go-sql-driver/mysql"

)

func main()  {

	conns := []string{
		"mysql", "root:passwd@tcp(127.0.0.1:3306)/dabase_name?timeout=3s&parseTime=true&loc=Local&charset=utf8",
		"mysql", "root:passwd@tcp(127.0.0.1:3306)/dabase_name?timeout=3s&parseTime=true&loc=Local&charset=utf8",
		"mysql", "root:passwd@tcp(127.0.0.1:3306)/dabase_name?timeout=3s&parseTime=true&loc=Local&charset=utf8",
	}

	engine, err := xorm.NewEngineGroup("mysql", conns)
	
	
	if err !=nil{
		return
	}
	engine.Ping()  // 可以判斷是否能連接

	defer engine.Close()  // 退出后關閉
}

連接池  

  engine內部支持連接池接口和對應的函數。

  • 如果需要設置連接池的空閑數大小,可以使用engine.SetMaxIdleConns()來實現。
  • 如果需要設置最大打開連接數,則可以使用engine.SetMaxOpenConns()來實現。

 

詳細查詢操作可參照github,鏈接  https://github.com/go-xorm/xorm/

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM