事务
事务处理是数据的重要特性,对于一些支付系统,事务对业务逻辑会有重要影响。golang的mysql驱动也封装好了事务相关的操作,一般使用的是db对象的方法,事务则是使用另外一个对象,sql.Tx对象。
使用db的Begin方法可以创建tx对象,用法和db的相关用法类似。一旦创建了tx对象,事务处理都依赖与tx对象,这个对象会从连接池中取出一个空闲的连接,接下来的sql执行都基于这个连接,直到commit或者rollback调用之后,才会把连接释放到连接池。
在事务处理的时候,不能使用db的查询方法,虽然后者可以获取数据,可是这不属于同一个事务处理,将不会接受commit和rollback的改变,事务的连接生命周期从Beigin函数调用起,直到Commit和Rollback函数的调用结束
db和tx初始化
package mysqltx
type Ip struct {
UUID string `gorm:"column:id" json:"uuid"`
IP string `gorm:"column:ip" json:"ip"`
MAC string `gorm:"column:mac" json:"mac"`
}
func (User) TableName() string {
return "ips"
}
// *** 通过tx的方式初始化数据库 ***
tx := db.Begin()
defer func() {
if err != nil {
tx.Rollback()
}
}()
// 查询
var ips []Ip
err := tx.Where("uuid = ?","3333feeb52eb425593231247fead95c5").Find(&ips).Error
// 创建
ip := &Ip{UUID:"3333feeb52eb425593231247fead95c5",IP:"192.168.1.1"}
err := tx.Create(ip).Error
//删除
ip := &Ip{UUID:"3333feeb52eb425593231247fead95c5",IP:"192.168.1.1"}
err := tx.Delete(ip).Error
//提交,注意对tx创建操作后一定要commit,否则程序不会报错,但数据库也未创建成功
err := tx.Commit().Error
// *** 通过db的方式初始化数据库 ***
import "github.com/jinzhu/gorm"
var db *gorm.DB
func initdb() {
// 第一个参数:数据库类型(mysql,postgres)
// 第二个参数:数据库连接,用户名:密码@protocal(ip:port)
conn := "root:root@tcp(192.168.1.12:3306)?charset=Utf8&parseTime=true&loc=Local"
db,err := gorm.Open("mysql", conn)
defer db.Close()
//SetMaxOpenConns用于设置最大打开的连接数
//SetMaxIdleConns用于设置闲置的连接数
db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
}
db和tx对比
// 对比db和tx查询
rows, _ := db.Query("SELECT uuid FROM ips")
for rows.Next() {
var mid, did int
rows.Scan(&mid)
db.QueryRow("SELECT id FROM detail_user WHERE master = ?", mid).Scan(&did)
}
调用了Query方法之后,在Next方法中取结果的时候,rows是维护了一个连接,再次调用QueryRow的时候,db会再从连接池取出一个新的连接。rows和db的连接两者可以并存,并且相互不影响。但若失通过tx的方式实现时无法实现二次查询的,因为第一次的查询并没有被释放,无法执行下一次查询
场景分析
func delete(){
//1、通过事务删除一条数据
ip := &Ip{UUID:"3333feeb52eb425593231247fead95c5",IP:"192.168.1.1"}
err := tx.Delete(ip).Error
//2、通过db查询该数据
ip := Ip{}
err := db.Where("uuid= 3333feeb52eb425593231247fead95c5").First(&ip)
}
上述情况仍会在数据库查询到数据,因为删除是通过事务完成的,查询是通过db,调用的不是同一个连接,导致数据不同步,所以建议一个处理流程中选择完整的tx或db,不要穿插使用