xorm
中文
Xorm is a simple and powerful ORM for Go.
Features
-
Struct <-> Table Mapping Support
-
Chainable APIs
-
Transaction Support
-
Both ORM and raw SQL operation Support
-
Sync database schema Support
-
Query Cache speed up
-
Database Reverse support, See Xorm Tool README
-
Simple cascade loading support
-
Optimistic Locking support
-
SQL Builder support via xorm.io/builder
-
Automatical Read/Write seperatelly
-
Postgres schema support
-
Context Cache support
Drivers Support
Drivers for Go's sql package which currently support database/sql includes:
Installation
go get github.com/go-xorm/xorm
Documents
Quick Start
engine, err := xorm.NewEngine(driverName, dataSourceName)
- Define a struct and Sync2 table struct to database
type User struct {
Id int64
Name string
Salt string
Age int
Passwd string `xorm:"varchar(200)"`
Created time.Time `xorm:"created"`
Updated time.Time `xorm:"updated"`
}
err := engine.Sync2(new(User))
dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName}
engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice)
masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName)
slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName)
slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName)
engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine})
Then all place where engine
you can just use engineGroup
.
Query
runs a SQL string, the returned results is []map[string][]byte
, QueryString
returns []map[string]string
, QueryInterface
returns []map[string]interface{}
.
results, err := engine.Query("select * from user")
results, err := engine.Where("a = 1").Query()
results, err := engine.QueryString("select * from user")
results, err := engine.Where("a = 1").QueryString()
results, err := engine.QueryInterface("select * from user")
results, err := engine.Where("a = 1").QueryInterface()
Exec
runs a SQL string, it returns affected
and error
affected, err := engine.Exec("update user set age = ? where name = ?", age, name)
Insert
one or multiple records to database
affected, err := engine.Insert(&user)
affected, err := engine.Insert(&user1, &user2)
affected, err := engine.Insert(&users)
affected, err := engine.Insert(&user1, &users)
Get
query one record from database
has, err := engine.Get(&user)
has, err := engine.Where("name = ?", name).Desc("id").Get(&user)
var name string
has, err := engine.Table(&user).Where("id = ?", id).Cols("name").Get(&name)
var id int64
has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id)
has, err := engine.SQL("select id from user").Get(&id)
var valuesMap = make(map[string]string)
has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap)
var valuesSlice = make([]interface{}, len(cols))
has, err := engine.Table(&user).Where("id = ?", id).Cols(cols...).Get(&valuesSlice)
Exist
check if one record exist on table
has, err := testEngine.Exist(new(RecordExist))
has, err = testEngine.Exist(&RecordExist{
Name: "test1",
})
has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{})
has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist()
has, err = testEngine.Table("record_exist").Exist()
has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist()
Find
query multiple records from database, also you can use join and extends
var users []User
err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users)
type Detail struct {
Id int64
UserId int64 `xorm:"index"`
}
type UserDetail struct {
User `xorm:"extends"`
Detail `xorm:"extends"`
}
var users []UserDetail
err := engine.Table("user").Select("user.*, detail.*").
Join("INNER", "detail", "detail.user_id = user.id").
Where("user.name = ?", name).Limit(10, 0).
Find(&users)
Iterate
and Rows
query multiple records and record by record handle, there are two methods Iterate and Rows
err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
user := bean.(*User)
return nil
})
err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error {
user := bean.(*User)
return nil
})
rows, err := engine.Rows(&User{Name:name})
defer rows.Close()
bean := new(Struct)
for rows.Next() {
err = rows.Scan(bean)
}
Update
update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on.
affected, err := engine.ID(1).Update(&user)
affected, err := engine.Update(&user, &User{Name:name})
var ids = []int64{1, 2, 3}
affected, err := engine.In("id", ids).Update(&user)
affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12})
affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12})
affected, err := engine.ID(1).AllCols().Update(&user)
Delete
delete one or more records, Delete MUST have condition
affected, err := engine.Where(...).Delete(&user)
affected, err := engine.ID(2).Delete(&user)
counts, err := engine.Count(&user)
FindAndCount
combines function Find
with Count
which is usually used in query by page
var users []User
counts, err := engine.FindAndCount(&users)
agesFloat64, err := engine.Sum(&user, "age")
agesInt64, err := engine.SumInt(&user, "age")
sumFloat64Slice, err := engine.Sums(&user, "age", "score")
sumInt64Slice, err := engine.SumsInt(&user, "age", "score")
err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users)
- Multiple operations in one go routine, no transation here but resue session memory
session := engine.NewSession()
defer session.Close()
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
return nil
- Transation should on one go routine. There is transaction and resue session memory
session := engine.NewSession()
defer session.Close()
if err := session.Begin(); err != nil {
return err
}
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return err
}
return session.Commit()
- Or you can use
Transaction
to replace above codes.
res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) {
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
if _, err := session.Insert(&user1); err != nil {
return nil, err
}
user2 := Userinfo{Username: "yyy"}
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
return nil, err
}
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
return nil, err
}
return nil, nil
})
- Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session.
sess := engine.NewSession()
defer sess.Close()
var context = xorm.NewMemoryContextCache()
var c2 ContextGetStruct
has, err := sess.ID(1).ContextCache(context).Get(&c2)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c2.Id)
assert.EqualValues(t, "1", c2.Name)
sql, args := sess.LastSQL()
assert.True(t, len(sql) > 0)
assert.True(t, len(args) > 0)
var c3 ContextGetStruct
has, err = sess.ID(1).ContextCache(context).Get(&c3)
assert.NoError(t, err)
assert.True(t, has)
assert.EqualValues(t, 1, c3.Id)
assert.EqualValues(t, "1", c3.Name)
sql, args = sess.LastSQL()
assert.True(t, len(sql) == 0)
assert.True(t, len(args) == 0)
Contributing
If you want to pull request, please see CONTRIBUTING. And we also provide Xorm on Google Groups to discuss.
Credits
Contributors
This project exists thanks to all the people who contribute. [Contribute].
Backers
Thank you to all our backers! 🙏 [Become a backer]
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor]
Changelog
-
v0.7.0
-
v0.6.6
-
v0.6.5
- Postgres schema support
- vgo support
- Add FindAndCount
- Database special params support via NewEngineWithParams
- Some bugs fixed
-
v0.6.4
- Automatical Read/Write seperatelly
- Query/QueryString/QueryInterface and action with Where/And
- Get support non-struct variables
- BufferSize on Iterate
- fix some other bugs.
More changes ...
Cases
LICENSE
BSD License http://creativecommons.org/licenses/BSD/