为什么使用defer stmnt.Close()会阻塞我的http.Redirect呢?

huangapple go评论71阅读模式
英文:

Why does defer stmnt.Close() seem to block my http.Redirect?

问题

为什么我的 defer stmnt.Close() 看起来会阻塞我的 http.Redirect,导致网站无限加载而无法重定向?

但是如果我移除 defer stmnt.Close(),重定向就能正常工作?

err = db.QueryRow("SELECT steamid FROM accounts WHERE steamid = ?", ids).Scan(&steamid)
if err != nil {
    common.WriteLog(err.Error(), r)
    http.Error(w, "Failed to connect to database. Try again in a bit.", 500)
}

switch {
case len(profile.Response.Players) == 0:
    common.WriteLog("Failed to look you up in the steam database. Try again in a bit.", r)
    http.Error(w, "Failed to look you up in the steam database. Try again in a bit.", 500)
case err == sql.ErrNoRows:
    stmnt, err := db.Query("INSERT INTO accounts SET steamid=?", ids)
    if err != nil {
        common.WriteLog(err.Error(), r)
        http.Error(w, "Failed to insert your account to the database. Try again in a bit.", 500)
    }
    defer stmnt.Close() // <<<< The suspect
    // Insert Account

    http.Redirect(w, r, "/", 303)
case err != nil:
    common.WriteLog(err.Error(), r)
    http.Error(w, "Failed to insert your account to the database. Try again in a bit.", 500)

default:
    // Login User

    http.Redirect(w, r, "/", 303)

}

你的代码中使用了 defer stmnt.Close() 来延迟关闭数据库连接。defer 关键字会在函数返回之前执行 Close() 方法。然而,如果在执行 defer stmnt.Close() 之前发生了重定向,那么 Close() 方法将会被阻塞,导致重定向无法正常进行。

通过移除 defer stmnt.Close(),你可以解决这个问题,因为数据库连接会在函数结束时自动关闭。这样,重定向就能够正常工作了。

英文:

Why does my defer stmnt.Close() seem to block my http.Redirect from redirecting it just hangs on the website infinitely trying to load.

But if I remove the defer stmnt.Close() it redirects just fine?

    err = db.QueryRow(&quot;SELECT steamid FROM accounts WHERE steamid = ?&quot;, ids).Scan(&amp;steamid)
	if err != nil {
		common.WriteLog(err.Error(), r)
		http.Error(w, &quot;Failed to connect to database. Try again in a bit.&quot;, 500)
	}

	switch {
	case len(profile.Response.Players) == 0:
		common.WriteLog(&quot;Failed to look you up in the steam database. Try again in a bit.&quot;, r)
		http.Error(w, &quot;Failed to look you up in the steam database. Try again in a bit.&quot;, 500)
	case err == sql.ErrNoRows:
		stmnt, err := db.Query(&quot;INSERT INTO accounts SET steamid=?&quot;, ids)
		if err != nil {
			common.WriteLog(err.Error(), r)
			http.Error(w, &quot;Failed to insert your account to the database. Try again in a bit.&quot;, 500)
		}
		defer stmnt.Close() // &lt;&lt;&lt;&lt;&lt; The suspect
		// Insert Account

		http.Redirect(w, r, &quot;/&quot;, 303)
	case err != nil:
		common.WriteLog(err.Error(), r)
		http.Error(w, &quot;Failed to insert your account to the database. Try again in a bit.&quot;, 500)

	default:
		// Login User

		http.Redirect(w, r, &quot;/&quot;, 303)

	}

答案1

得分: 3

使用db.Exec而不是db.Query

> Exec执行一个查询,不返回任何行。

> Query执行一个返回行的查询。

至于为什么,我猜测mysql的Rows.Close正在等待数据在连接上

func (rows *mysqlRows) Close() error {
	mc := rows.mc
	if mc == nil {
		return nil
	}
	if mc.netConn == nil {
		return ErrInvalidConn
	}

	// 从流中删除未读的数据包
	err := mc.readUntilEOF()
	rows.mc = nil
	return err
}

这是永远不会发生的。

参见这个示例。

英文:

Use db.Exec instead of db.Query.

> Exec executes a query without returning any rows.

vs

> Query executes a query that returns rows

As for why, I would guess the mysql Rows.Close is waiting for data on the connection:

func (rows *mysqlRows) Close() error {
	mc := rows.mc
	if mc == nil {
		return nil
	}
	if mc.netConn == nil {
		return ErrInvalidConn
	}

	// Remove unread packets from stream
	err := mc.readUntilEOF()
	rows.mc = nil
	return err
}

Which is never going to happen.

See this for example.

huangapple
  • 本文由 发表于 2015年9月4日 08:39:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/32387502.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定