1

when i use golang to query mysql, sometimes i found "deadlock err" in my code.

my question is not "why deadlock occurred", but why deadlock err found in "err = rows.Err()". in my mind, if deadlock occurred, i should get it at "tx.Query"'s return err.

this is demo code, "point 2" is where deadlock error occurred


func demoFunc(tx *sql.Tx, arg1, arg2 int) ([]outItem, error) {
    var ret []outItem
    var err error
    var rows *sql.Rows

    //xxxLockSql may deadlock, so try again for 3-times
    for i := 0; i < 3; i++ {
        //------ point 1
        rows, err = tx.Query(xxxLockSql, arg1, arg2)
        if err == nil {
            break
        }

        log.Printf("[ERROR] xxxLockSql failed, err %s, retry %d", err.Error(), i)
        time.Sleep(time.Millisecond * 10)
    }

    //if query xxxLockSql failed up to 3-times, then return
    if err != nil {
        log.Printf("[ERROR] xxxLockSql failed, err %s", err.Error())
        return ret, err
    }

    defer rows.Close()

    for rows.Next() {
        err = rows.Scan(&a1, &a2)
        if err != nil {
            return ret, err
        }

        ret = append(ret, acl)
    }

    //------ point 2
    if err = rows.Err(); err != nil {
        // i found deadlock err in this "if" segment.
        // err content is "Error 1213: Deadlock found when trying to get lock; try restarting transaction" 
        log.Printf("[ERROR] loop rows failed, err %s", err.Error())
        return ret, err
    }

    return ret, nil
}

1 Answers1

2

I cannot be sure about the reason since you did not mention your database driver (and which sql package you are using). But I think this is because sql.Query is lazy, which means querying and loading the rows is postponed until actual use, i.e., rows.Next() - that is why the deadlock error occurs there.

As of why it is out of the loop, it's because that when an error occurs, rows.Next() returns false and break the loop.

leaf bebop
  • 7,643
  • 2
  • 17
  • 27