Golang中如何访问Statement中的值

Golang中如何访问Statement中的值

package main

import (
    "database/sql"
    "fmt"
  _ "vNext/go_ibm_db"
)

func main() {
    con := "HOSTNAME=localhost;PORT=50000;DATABASE=dbname;UID=uname;PWD=password"
    db, err := sql.Open("go_ibm_db", con)
    if err != nil {
        fmt.Println(err)
    }
    db.Exec("Create table dbtype2(a int,c float)")
    st,err:=db.Prepare("Insert into dbtype2(a,c) values(?,?)")
	if err != nil{
	fmt.Println(err)
	}
	st.Query(12,3.45)
}

我想要访问st中的一个变量(语句句柄)。但当我尝试访问它时,提示该变量未导出。是否有其他方法可以访问它。

谢谢。


更多关于Golang中如何访问Statement中的值的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

引用 akhilravuri:

访问其中未导出的变量

不。

更多关于Golang中如何访问Statement中的值的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


当我们调用 db.Prepare() 时,它会在内部创建一个语句句柄,然后运行 SQL 接口。有没有办法将该句柄传递给应用程序?

db` 甚至没有 `Execute` 方法,根据我个人的类型推断脑算法...

因此我认为这是个拼写错误,你实际想说的是 `Exec`。

不管怎样...你说的 "in st" 是什么意思?

`st` 是一个 `database/sql/Result` 类型的变量...这是一个接口,所以它没有字段,只有两个方法。但如果你已经实现了具体类型,那么你可以直接在实现中访问它的字段,无论该字段是否导出。

抱歉,应该是

func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
return db.ExecContext(context.Background(), query, args...)
}

database/sql 包中的 Exec 函数

type Stmt struct {
	// Immutable:
	db        *DB    // where we came from
	query     string // that created the Stmt
	stickyErr error  // if non-nil, this error is returned for all operations
	closemu sync.RWMutex // held exclusively during close, for read otherwise.
	cg   stmtConnGrabber
	cgds *driverStmt
	parentStmt *Stmt
	mu     sync.Mutex // protects the rest of the fields
	closed bool
	css []connStmt
	lastNumClosed uint64
}

st 是一个通过 db.Prepare() 返回的 Stmt 对象 有没有办法访问其中未导出的变量?

在Go语言的database/sql包中,Stmt类型的内部字段(如语句句柄)通常被设计为未导出字段,这是出于封装和抽象数据库驱动实现的考虑。不过,你可以通过类型断言来访问特定驱动提供的导出方法或字段,前提是驱动支持。

对于go_ibm_db驱动,Stmt的实际类型可能是*go_ibm_db.OCI8Stmt(具体类型名可能因驱动版本而异)。你需要检查驱动文档或源代码,确认是否有导出字段或方法允许访问语句句柄。以下是一个示例方法,假设驱动提供了GetStmtHandle方法(实际方法名可能不同):

package main

import (
    "database/sql"
    "fmt"
    "reflect"
    _ "vNext/go_ibm_db"
)

func main() {
    con := "HOSTNAME=localhost;PORT=50000;DATABASE=dbname;UID=uname;PWD=password"
    db, err := sql.Open("go_ibm_db", con)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer db.Close()

    // 创建表并准备语句
    _, err = db.Exec("CREATE TABLE dbtype2(a INT, c FLOAT)")
    if err != nil {
        fmt.Println(err)
        return
    }

    st, err := db.Prepare("INSERT INTO dbtype2(a, c) VALUES(?, ?)")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer st.Close()

    // 使用反射检查 st 的实际类型
    fmt.Printf("stmt type: %v\n", reflect.TypeOf(st))

    // 尝试类型断言到驱动特定类型
    if driverStmt, ok := st.(interface{ GetStmtHandle() interface{} }); ok {
        handle := driverStmt.GetStmtHandle()
        fmt.Printf("Statement handle: %v\n", handle)
    } else {
        fmt.Println("驱动未提供 GetStmtHandle 方法")
    }

    // 执行插入操作
    _, err = st.Exec(12, 3.45)
    if err != nil {
        fmt.Println(err)
    }
}

如果驱动没有提供直接访问句柄的方法,你可能需要修改驱动代码或使用反射强制访问未导出字段(不推荐,因为可能破坏封装和兼容性)。例如,使用反射访问假设的stmtHandle字段:

// 注意:此方法依赖于驱动内部结构,可能随版本变化而失效
v := reflect.ValueOf(st).Elem()
if v.Kind() == reflect.Struct {
    f := v.FieldByName("stmtHandle") // 字段名需根据驱动实际名称调整
    if f.IsValid() && f.CanInterface() {
        handle := f.Interface()
        fmt.Printf("Statement handle: %v\n", handle)
    }
}

在实际应用中,建议优先查阅go_ibm_db驱动的文档或源代码,确认支持的接口。如果驱动未设计导出句柄,可能需要通过其他方式(如驱动提供的特定函数)实现你的需求。

回到顶部