GORM的使用入门
通过GORM存储自定义的数据
如果你想把结构体,数组等非常规数据类型存放进数据库,并且在取出来的时候让知道GORM该如何接受。我们可以采用自定义数据类型来实现。
如果想使用自定义数据类型,需要实现Scanner和Value接口。Value接口可以告知GORM如何把非常规数据存放进数据库,而Scanner接口则告知GORM怎么去从数据库取出自定义数据类型。
例如,我们可以将结构体转换成json格式存放入数据库当中。
json: Javascript Object Nanotation 是一种数据交换格式,常用于前后端数据传输。前后端可以将需要通信的内容转换成json字符串,另一端再解析字符串成对应的数据结构,如struct结构,从而完成通信。
假设我们定义结构体如下:
type UserInfo struct {
Name String `json:"name"`
Age int `json:"age"`
通过已经实现了的Value接口,将结构体存放入数据库当中:
func (u UserInfo) Value() (driver.Value, error) {
return json.Marshal(u)
}
json.Marshal():将数据编码成json字符串。注意:必须要是可导出成员才能被编码,即结构体首字母应大写。如果字段后有json标签,则用标签名作为json的Key,否则直接用字段名作为Key。
再定义Scanner结构,将数据从数据库中读出。
func (u *UserInfo) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
info := UserInfo{}
err := json.Unmarshal(bytes, &info)
*u = info
return err
}
json.Unmarshal:和json.Marshal()相对应,将json字符串解码到对应的数据结构。例如上面例子就将传入的json字符串内容解码到了UserInfo结构体。
注意:json.Unmarshal接收体必须要传入指针,虽然不会报错,但无法对info实例进行赋值。如果有匹配不了的项会自动忽略。
type User struct {
ID uint
Info UserInfo `gorm:"type:string"`
}
对此结构体进行数据插入的时候,gorm自动会将UserInfo结构体转化为纯字符串放入数据库当中。
DB.Create(&User{
ID: 1,
Info: UserInfo{
Name: "xxx",
Age: 21,
},
})
事务
事务就是用户定义的一系列数据库操作,这些操作可以视为一个完整的逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元。
一个很常见的例子便是银行转账,张三给李四转账100元,在程序里面,张三的余额就要-100,李四的余额就要+100,整个事件是一个不可分割的整体。假如说有哪一步执行出错,例如张三的余额没有成功减去100,就会导致银行的总账目对不上。
在gorm中,为了确保数据一致性,会在事务里执行写入操作(创建、更新、删除),一般是默认为开启状态。
禁用gorm默认事务之后,可以得到性能上30%左右的提升。
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
SkipDefaultTransaction: true,
})
gorm可以使用Transaction()方法定义事务,如
DB.Transaction(func(tx *gorm.DB) error {
zhangsan.Money -= 100
err := tx.Model(&zhangsan).Update("money", zhangsan.Money).Error
if err != nil {
return err
}
lisi.Money += 100
err = tx.Model(&lisi).Update("money", lisi.Money).Error
if err != nil {
return err
}
return nil
})
这样,加入程序出现错误,就会自动回滚到开始状态,不会出现数据不一致的情况。
Transaction() 也可以进行嵌套。
除了使用 Transaction 方法之外,也可以使用手动方法定义事务。
首先需要使用 tx := database.Begin 开始事务。
tx.Create(...) 在事务中执行一些数据库操作,注意,需要使用之前定义的'tx'而不是'database'。不仅是 Create 方法,常用的数据库方法都可以使用,在事务里面完成增删改查等操作。
操作遇到错误的时候,需要使用 tx.Rollback 回滚事务,保证数据一致性。
如果没有遇到任何错误,便可以将事务进行提交 tx.Commit。
另外,GORM 提供了 SavePoint、Rollbackto 方法,来提供保存点以及回滚至保存点功能