因为gorm支持级联查询。xorm的jion查询虽然很棒,但是查出来的不能生成嵌套结构体。而gorm就可以,经过摸索,这种关联啊,预加载啊,虽然没搞清楚他们之间的区别,但总算能满足自己的查询需要了。
网络上都是单条记录的关联查询,而我需要对多条记录进行关联查询,目前只知道使用preload
//查询某个用户打赏记录
func GetUserPay(uid int64, limit, offset int) (pays []*Pay, err error) {
//获取DB
db := GetDB()
// err = db.Where("user_id", uid).Find(&pays).Error
err = db.Model(&pays).Preload("User").Preload("Article").Where("user_id=?", uid).Limit(limit).Offset(offset).Find(&pays).Error //查询所有device记录
// err = db.Model(&pays).Related(&pays.User, "Users").Error
return pays, err
// 多连接及参数
// db.Joins("JOIN pays ON pays.user_id = users.id", "jinzhu@example.org").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("user_id = ?", uid).Find(&pays)
}
还有就是连接池,因为在beego中用,除了beego的orm外,还用了xorm,这次再加入gorm,就3个了,他们如何连接数据库也是费了不少心思。说gorm用连接池,每次使用的时候要调用一下?
使用了gorm的事务,作为小程序赞赏时,用户账户扣款,文章获得赞赏,用户账户余额减少。
//添加某个文章某个用户打赏记录
func AddUserPay(articleid, uid int64, amount int) error {
//获取DB
db := GetDB()
// 注意,当你在一个事务中应使用 tx 作为数据库句柄
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
}
}()
if err := tx.Error; err != nil {
return err
}
//保证文章id正确
var article Article
err := db.Where("id = ?", articleid).First(&article).Error
if err != nil {
tx.Rollback()
return err
}
// user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
// db.Create(&user)
if err := tx.Create(&Pay{UserID: uid, ArticleID: articleid, Amount: amount}).Error; err != nil {
tx.Rollback()
return err
}
//更新用户账户余额money
//1.首先保证账户存在
// money := Money{UserID: uid}
var money Money
err = db.Where("user_id = ?", uid).First(&money).Error
if err != nil {
tx.Rollback()
return err
}
//2.用户账户余额保证大于0
newamount := money.Amount - amount
if newamount < 0 {
tx.Rollback()
return err
}
//3.账户修改余额
rowsAffected := tx.Model(&money).Update("amount", newamount).RowsAffected
if rowsAffected == 0 {
tx.Rollback()
return nil
}
return tx.Commit().Error
}
连接池的问题:
//定义全局的db对象,我们执行数据库操作主要通过他实现。
var _db *gorm.DB
func init() {
var err error
var dns string
db_type := beego.AppConfig.String("db_type")
db_name := beego.AppConfig.String("db_name")
db_path := beego.AppConfig.String("db_path")
if db_path == "" {
db_path = "./"
}
dns = fmt.Sprintf("%s%s.db", db_path, db_name)
_db, err = gorm.Open(db_type, dns)
// _db.LogMode(true)
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
// defer gdb.Close()
//禁止表名复数形式
_db.SingularTable(true)
// 开发的时候需要打开调试日志
// _db.LogMode(true)
//设置数据库连接池参数
_db.DB().SetMaxOpenConns(100) //设置数据库连接池最大连接数
_db.DB().SetMaxIdleConns(20) //连接池最大允许的空闲连接数,如果没有sql任务需要执行的连接数大于20,超过的连接会被连接池关闭。
_db.CreateTable(&Pay{}, &Money{}, &Recharge{})
// if !gdb.HasTable(&Pay1{}) {
// if err = gdb.CreateTable(&Pay1{}).Error; err != nil {
// panic(err)
// }
// }
}
//获取gorm db对象,其他包需要执行数据库查询的时候,只要通过tools.getDB()获取db对象即可。
//不用担心协程并发使用同样的db对象会共用同一个连接,
// db对象在调用他的方法的时候会从数据库连接池中获取新的连接
// 注意:使用连接池技术后,千万不要使用完db后调用db.Close关闭数据库连接,
// 这样会导致整个数据库连接池关闭,导致连接池没有可用的连接
func GetDB() *gorm.DB {
return _db
}