gorm数据库连接的一些情况说明

本人最近用go写业务后台,数据库是mysql,用的是gorm连接,一般而言,是数据库先启动,再启动业务后台服务。
本人在程序启动的时候,会事先进行数据库连接。
下面是我发现的现象:
1.数据库先启动,再启动业务后台,业务操作正常,此时断掉数据库,业务操作异常(数据库操作报错), 此时启动数据库,再进行业务请求,业务操作正常(数据库请求正常)。

2.业务后台先启动,数据库后启动,此时业务操作异常(数据库操作报错)

很明显,现象1是我想要的结果,断掉数据库后再重新启动数据库,gorm内部给人感觉会自动重连一样。
但是现象2很明显不是想要的效果,没有自动重连的感觉。

本人将调试时发现的情况给予说明

如下所示,是打开数据库的gorm调用,出问题的情况下,我的代码里面只会调用一次。

func Open(dialect string, args ...interface{}) (db *DB, err error) {
	if len(args) == 0 {
		err = errors.New("invalid database source")
		return nil, err
	}
	var source string
	var dbSQL SQLCommon
	var ownDbSQL bool

	switch value := args[0].(type) {
	case string:
		var driver = dialect
		if len(args) == 1 {
			source = value
		} else if len(args) >= 2 {
			driver = value
			source = args[1].(string)
		}
		dbSQL, err = sql.Open(driver, source)
		ownDbSQL = true
	case SQLCommon:
		dbSQL = value
		ownDbSQL = false
	default:
		return nil, fmt.Errorf("invalid database source: %v is not a valid type", value)
	}

	db = &DB{
		db:        dbSQL,
		logger:    defaultLogger,
		callbacks: DefaultCallback,
		dialect:   newDialect(dialect, dbSQL),
	}
	db.parent = db
	if err != nil {
		return
	}
	// Send a ping to make sure the database connection is alive.
	if d, ok := dbSQL.(*sql.DB); ok {
		if err = d.Ping(); err != nil && ownDbSQL {
			d.Close()
		}
	}
	return
}

当数据库先启动时,业务程序后启动时,代码走到d, ok := dbSQL.(*sql.DB),sql.DB类型的变量正常,里面的closed变量为false,代表打开状态。
在这里插入图片描述
后面就算关闭掉数据库,该sql.DB里面的closed依然为false,代表数据库是打开的。

当数据库后启动时,业务程序先启动时,代码走到d, ok := dbSQL.(*sql.DB),sql.DB类型的变量异常,会进入到d.Close()逻辑中去,此时DB里面的closed变量为true,代表关闭状态。
后面就算关闭掉数据库,该sql.DB里面的closed依然为true,代表数据库是关闭的。

而下面database/sql/sql.go里面的一段代码代表,如果数据库是打开的,若没有正常可用的连接,依然会创建连接;如果数据库是关闭的,则直接返回错误。
在这里插入图片描述
并且多提一嘴:上面现象1情况时,若断掉数据库,gorm并没有去主动尝试连接,而是当我发起新的业务请求,后台需要操作数据库时,才会检测有无可用连接,此时才会创建新的连接。

根据上面的现象,下面是我给出针对现象2的解决方法。
解决方法就是:打开数据库失败时,代表数据库没启动,此时标记打开失败,后面在业务请求来的时候,判断数据库有无打开,若无打开,重新打开即可。

下面贴出一些关键代码,DbCheck是gin的中间件,当有新的业务请求来的时候,会首先检测有无打开的gorm,若无,则打开数据库。同时,下面的Init在服务程序启动的时候,就会被调用。正常情况下,DbCheck里面的Init不会被调用到

var (
	dbGorm *gorm.DB
)

func DbCheck() gin.HandlerFunc {
	return func(c *gin.Context) {
		if dbGorm == nil {
			Init()
		}

		c.Next()
	}
}

func Init() {
	var err error
	var ip, port, username, password, dbName string
	ip, err = config.GetValueStr("mysql", "ip")
	port, err = config.GetValueStr("mysql", "port")
	username, err = config.GetValueStr("mysql", "username")
	password, err = config.GetValueStr("mysql", "password")
	dbName, err = config.GetValueStr("mysql", "db")

	var portInt int
	portInt, err = strconv.Atoi(port)

	dbGorm, err = DbConn(username, password, ip, dbName, portInt)
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("connnect db succeed")
		//dbGorm.CreateTable(&model.OUserInfo{})
	}

}

func GetDB() (db *gorm.DB) {
	return dbGorm
}

func DbConn(MyUser, Password, Host, Db string, Port int) (db *gorm.DB, err error) {
	connArgs := fmt.Sprintf("%s:%s@(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", MyUser, Password, Host, Port, Db)
	db, err = gorm.Open("mysql", connArgs)
	if err != nil {
		if db != nil {
			db.Close()
			db = nil
		}

		return
	}
	db.SingularTable(true)
	return
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值