创作不易感谢支持。
一条主写Go和PHP的小菜鸟。平常有时间喜欢自己写点东西,如有不对的地方,欢迎大佬指点。 个人博客:太阳上的雨天 地址:http://blog.caixiaoxin.cn 善于分享,希望有助他人. 非常感谢各位大佬的关注和支持
xorm 一个简单强大的Go语言ORM库。通过它让操作数据库变得更加简单。
XORM关系映射,只是Go操作数据库的其中之一。比如还有GORM。至于两者的区别,一搜一大堆,不再介绍。
这里只介绍一下XORM的基本使用。
go get -u github.com/go-sql-driver/mysql
go get -u github.com/xormplus/xorm
指责
结构体名称 ----- 表名
结构体字段 ------ 表字段
结构体字段属性 ----- 对象的表子段属性
go type’s kind | value method | xorm type |
---|---|---|
implemented Conversion | Conversion.ToDB / Conversion.FromDB | Text |
int, int8, int16, int32, uint, uint8, uint16, uint32 | Int | |
int64, uint64 | BigInt | |
float32 | Float | |
float64 | Double | |
complex64, complex128 | json.Marshal / json.UnMarshal | Varchar(64) |
[]uint8 | Blob | |
array, slice, map except []uint8 | json.Marshal / json.UnMarshal | Text |
string | Varchar(255) | |
time.Time | DateTime | |
cascade struct | primary key field value | BigInt |
struct | json.Marshal / json.UnMarshal | Text |
Others | Text | |
bool | 1 or 0 | Bool |
通过 core.NewPrefixMapper(core.SnakeMapper{}, “prefix”) 可以创建一个在SnakeMapper的基础上在命名中添加统一的前缀
例如,如果希望所有的表名都在结构体自动命名的基础上加一个前缀而字段名不加前缀,则可以在engine创建完成后执行以下语句:
tbMapper := core.NewPrefixMapper(core.SnakeMapper{}, "pre_")
engine.SetTableMapper(tbMapper)
执行之后,结构体 type User struct 默认对应的表名就变成了 pre_user 了,而之前默认的是 user
在xorm里面,可以同时存在多个Orm引擎,一个Orm引擎称为Engine,一个Engine一般只对应一个数据库
db/db.go
package db
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/xormplus/xorm"
)
var engine *xorm.Engine
func Init() *xorm.Engine {
engine, err := xorm.NewEngine("mysql", "root:root@/test?charset=utf8mb4")
if err != nil {
panic(err)
}
err = engine.Ping()
if err != nil {
fmt.Printf("connect ping failed: %v", err)
}
engine.ShowSQL(true)
return engine
}
先创建两张表,表比较简单,只是做演示使用
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) NOT NULL,
`password` varchar(100) NOT NULL,
`email` varchar(100) NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `address` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`addr` varchar(100) DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
写入一条数据
type Users struct {
Username string `xorm:"username"`
Password string `xorm:"password""`
Email string `xorm:"email"`
CreatedAt time.Time `xorm:"created"`
UpdatedAt time.Time `xorm:"updated"`
DeletedAt time.Time ` xorm:"deleted"`
}
func main() {
engine := db.Init()
u := &Users{}
u.Username = "test"
u.Password = "123456"
u.Email = "test@sina.com"
affected, err := engine.Insert(u)
if err != nil {
log.Fatal(fmt.Printf("insert into failed, err: %v", err))
}
fmt.Println(affected)
}
批量写入
使用slice
func main() {
engine := db.Init()
u := make([]Users, 2)
u[0].Username = "test2"
u[0].Password = "123456"
u[0].Email = "test2@sina.com"
u[1].Username = "test3"
u[1].Password = "123456"
u[1].Email = "test3@sina.com"
affected, err := engine.Insert(u)
if err != nil {
log.Fatal(fmt.Printf("insert into failed, err: %v", err))
}
fmt.Println(affected)
}
使用slice指针批量写入
func main() {
engine := db.Init()
u := make([]*Users, 2)
u[0] = &Users{}
u[0].Username = "test4"
u[0].Password = "123456"
u[0].Email = "test4@sina.com"
u[1] = &Users{}
u[1].Username = "test5"
u[1].Password = "123456"
u[1].Email = "test5@sina.com"
affected, err := engine.Insert(u)
if err != nil {
log.Fatal(fmt.Printf("insert into failed, err: %v", err))
}
fmt.Println(affected)
}
写入一条记录
type Users struct {
Username string `xorm:"username"`
Password string `xorm:"password""`
Email string `xorm:"email"`
CreatedAt time.Time `xorm:"created"`
UpdatedAt time.Time `xorm:"updated"`
DeletedAt time.Time `xorm:"deleted"`
}
type Address struct {
Addr string `xorm:"Addr"`
CreatedAt time.Time `xorm:"created"`
UpdatedAt time.Time `xorm:"updated"`
DeletedAt time.Time `xorm:"deleted"`
}
func main() {
engine := db.Init()
u := &Users{}
u.Username = "test4"
u.Password = "123456"
u.Email = "test4@sina.com"
a := &Address{}
a.Addr = "杭州"
affected, err := engine.Insert(u, a)
if err != nil {
log.Fatal(fmt.Printf("insert into failed, err: %v", err))
}
fmt.Println(affected)
}
批量写入
func main() {
engine := db.Init()
u := make([]*Users, 2)
u[0] = &Users{}
u[0].Username = "test6"
u[0].Password = "123456"
u[0].Email = "test4@sina.com"
u[1] = &Users{}
u[1].Username = "test7"
u[1].Password = "123456"
u[1].Email = "test5@sina.com"
a := make([]*Address, 2)
a[0] = &Address{}
a[0].Addr = "杭州"
a[1] = &Address{}
a[1].Addr = "上海"
affected, err := engine.Insert(u, a)
if err != nil {
log.Fatal(fmt.Printf("insert into failed, err: %v", err))
}
fmt.Println(affected)
}
Note: 这里的多表写入并没有使用事务。如果部分成功,部分失败不支持回滚
func main() {
engine := db.Init()
sql := "INSERT INTO users(username, password, email) values (?, ?, ?)"
res, err := engine.Exec(sql, "original", "123", "123@sina.com")
if err != nil {
log.Fatal(fmt.Printf("insert into failed, err: %v", err))
}
fmt.Println(res)
}
Note: 执行原生sql写入数据,created_at、updated_at时间的值不写的则为空。
原生sql写入还有其余三种方式,这里不再赘述
在Delete()时,deleted标记的字段将会被自动更新为当前时间而不是去删除该条记录
func main() {
engine := db.Init()
var u = &Users{}
u.Username = "test1"
affected, err := engine.Delete(u)
if err != nil {
log.Fatal(fmt.Printf("deleter into failed, err: %v", err))
}
fmt.Println(affected)
}
func main() {
engine := db.Init()
sql := "DELETE FROM users where id = ?"
affected, err := engine.Exec(sql, 1)
if err != nil {
log.Fatal(fmt.Printf("deleter into failed, err: %v", err))
}
fmt.Println(affected)
}
Note: 也可以使用原生sql update更新deleted_at时间为当前时间戳,实现软删除。
update方式
更新数据使用engine.Update方法,update的参数可以是一个结构体指针或者一个Map[string]interface{}类型。
func main() {
engine := db.Init()
engine.ID(13).Update(&Users{Username: "test"})
engine.ID(13).Cols("username", "email").Update(&Users{Username: "test2"}) // 会更新username和email两个子段,email为空
// map类型
affected, err := engine.Table(&Users{}).ID(13).Update(map[string]interface{}{
"username": "update_original",
})
if err != nil {
log.Fatal(fmt.Printf("update username failed, err: %v", err))
}
fmt.Println(affected)
}
执行原生sql更新数据
func main() {
engine := db.Init()
sql := "UPDATE users SET username = ?, updated_at = ? WHERE id = ?"
res, err := engine.Exec(sql, "aaa", time.Now().Format("2006-01-02 15:04:05"), 13)
if err != nil {
log.Fatal(fmt.Printf("update username failed, err: %v", err))
}
fmt.Println(res)
}
查询一条数据 - GET方法
func main() {
engine := db.Init()
// SELECT * FROM user LIMIT 1
user1 := &Users{}
has, _ := engine.ID(1).Get(user1)
if has {
fmt.Printf("user1:%v\n", user1)
}
// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1
user2 := &Users{}
has, _ = engine.Where("username = ?", "aaa").Desc("id").Get(user2)
if has {
fmt.Printf("user1:%v\n", user1)
}
}
查询多条数据 - Find 方法
Find()
需要传入对象切片的指针或 map 的指针
func main() {
engine := db.Init()
slicUsers := make([]Users, 0)
_ = engine.Find(&slicUsers)
fmt.Println(slicUsers)
mapUsers := make([]Users, 0)
engine.Where("username = ?", "aaa").Find(&mapUsers)
fmt.Println(mapUsers)
}
Iterate 效果与Find方法一样,对了一个回调函数处理每条记录
func main() {
engine := db.Init()
engine.Where("username = ?", "aaa").Iterate(new(Users), func(i int, bean interface{}) error {
users := bean.(*Users)
fmt.Println(users)
return nil
})
}
Count 统计满足条件的数量,参数为struct指针
func main() {
engine := db.Init()
count, _ := engine.Where("length(username) > ?", 3).Count(&Users{})
fmt.Println(count)
}
Rows方法 和 Iterate方法类似。
func main() {
engine := db.Init()
u := &Users{}
rows, _ := engine.Where("id > ?", 5).Rows(u)
defer rows.Close()
for rows.Next() {
rows.Scan(u)
fmt.Println(u)
}
}
写sql语句,然后执行即可。和更新删除类似,不再赘述。