美文网首页我爱编程
Golang+MySQL 事务

Golang+MySQL 事务

作者: 埃尔温薛定谔不养猫 | 来源:发表于2018-08-08 14:13 被阅读0次

    准备知识:MySQL事务

    1 基本操作

    sql.Tx

    tx会从连接池中取一个空闲的连接,直至调用commit或者rollback才会释放

    tx, err := db.Begin() // 创建tx对象
    
    tx.Query(command1)
    
    tx.Exec(command2)
    
    tx.Commit()
    

    2 并发

    事务只有一个连接,事务内的操作是串行

    db, _ := sql.Open(...)
    rows, _ := db.Query("SELECT id FROM tt_users")
    
    for rows.Next(){
        var (
            user_id int
            openid string
        )
        rows.Scan(&user_id)
        db.QueryRow("SELECT openid FROM tt_users_third WHERE user_id = ?", user_id).Scan(&openid)
    }
    

    这段代码在并发执行的时候QueryQueryRow是独立的两个连接。非tx对象的操作,每执行一个操作之前会从连接池取空闲连接。

    rows, _ := tx.Query("SELECT id FROM tt_users")
    
    for rows.Next(){
        var (
            user_id int
            openid string
        )
        rows.Scan(&user_id)
        tx.QueryRow("SELECT openid FROM tt_users_third WHERE user_id = ?", user_id).Scan(&openid)
    }
    

    tx执行完Query方法之后,连接转移到rows上,在Next方法中,tx.QueryRow将尝试获取该连接进行操作。因为还没有调用rows.Close(),因此连接还处于busy状态,tx无法进行QueryRow操作。这时候使用JOIN语句可以规避这个问题。

    3 实践

    事务处理过程中出现了异常为保证数据完整一致性和及时释放连接,需要rollback

    func tx_rollback(err error, tx *sql.Tx) {
        if err != nil {
            err = tx.Rollback()
            if err != nil {
                log.Println("tx.Rollback() Error:" + err.Error())
                return
            }
        }
    }
    
    tx, err := db.Begin()
            count = 0
            if err != nil {
                count += 1
                tx, err = db.Begin()
                if count > 3 {
                    errInfo := "db.Begin() Error:" + err.Error()
                    log.Println(errInfo)
                    CJSON(c, -1, errInfo)
                }
            }
    
            var (
                uid          int
                isRegistered bool
                isBound      bool
                openid       string
            )
    
            err = tx.QueryRow("SELECT id FROM tt_users WHERE phone = ?", phone).Scan(&uid)
            tx_rollback(err, tx)
            if uid != 0 {
                isRegistered = true
            }
    
            if isRegistered {
                err = tx.QueryRow("SELECT openid FROM tt_user_third WHERE user_id = ?", uid).Scan(&openid)
                tx_rollback(err, tx)
                if openid != "" {
                    isBound = true
                }
            }
            err = tx.Commit()
            tx_rollback(err, tx)
    

    这篇文章相当于下面参考文章的一个简单总结,感谢作者“人世间”的分享
    参考文章:https://www.jianshu.com/p/bc8120bec94e

    相关文章

      网友评论

        本文标题:Golang+MySQL 事务

        本文链接:https://www.haomeiwen.com/subject/kcotbftx.html