返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

queryrow

发布于 2024-10-12 19:15:51 字数 1595 浏览 0 评论 0 收藏 0

对 Query 进行包装,用于返回单条记录。

  • 没找到记录,返回 ErrNoRows
  • 方法 Row.Scan 主动释放连接。
package main

import (
	"database/sql"
	"log"

	_ "github.com/mattn/go-sqlite3"
)

func main() {
	log.SetFlags(log.Lshortfile)
    
	db, err := sql.Open("sqlite3", "./test.db")
	if err != nil { log.Fatalln(err) }
	defer db.Close()

    // ------------------
    
	q := `SELECT name FROM user WHERE id > ?`

	var name string
	err = db.QueryRow(q, 10).Scan(&name)

	if err == sql.ErrNoRows { 
		println("norow") 
        return
	} else if err != nil { 
		log.Fatalln(err) 
	}

	println(name)
}

源码剖析

调用 Query 返回 Rows 包装成 Row 单行记录。
Row.Scan 操作中,会调用 Rows.Close ,确保归还连接。

// database/sql/sql.go

func (db *DB) QueryRowContext(ctx, query string, args ...any) *Row {
	rows, err := db.QueryContext(ctx, query, args...)
	return &Row{rows: rows, err: err}
}
func (r *Row) Scan(dest ...any) error {
	if r.err != nil {
		return r.err
	}

    // 确保 rows.Close 调用,归还连接。
	defer r.rows.Close()
    
	for _, dp := range dest {
		if _, ok := dp.(*RawBytes); ok {
			return errors.New("sql: RawBytes isn't allowed on Row.Scan")
		}
	}

    // 没有记录。
	if !r.rows.Next() {
        
        // 检查是不是意外导致。
		if err := r.rows.Err(); err != nil {
			return err
		}
        
		return ErrNoRows
	}
    
	err := r.rows.Scan(dest...)
	if err != nil {
		return err
	}
    
	// Make sure the query can be processed to completion with no errors.
	return r.rows.Close()
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文