database / sql和database / sql / driver中的命名参数

时间:2020-12-20 18:03:02

I'm trying to figure out what the pattern is for using named parameters in go's built-in database/sql package. I looked at the oracle driver, but it seems like just a wrapper for the C library. Have people solved this in an elegant way? So far I've just worked around the problem by putting {0}, {1} as the parameters in the unit tests, but it sure would be nice to be able to use them normally as a map[string]interface{} or something. Does anyone have an idea or an implementation that seems idiomatic?

我试图弄清楚在go的内置数据库/ sql包中使用命名参数的模式是什么。我查看了oracle驱动程序,但它似乎只是C库的包装器。人们以优雅的方式解决了这个问题吗?到目前为止,我只是通过将{0},{1}作为单元测试中的参数来解决问题,但是能够将它们正常地用作map [string] interface {}或者确实很好。一些东西。有没有人有一个看似惯用的想法或实现?

For reference, here is a test:

供参考,这是一个测试:

db := testConn()
stmt, err := db.Prepare("return {0} as int1, {1} as int2")
if err != nil {
   t.Fatal(err)
}
rows, err := stmt.Query(123, 456)
if err != nil {
   t.Fatal(err)
}
rows.Next()

var test int
var test2 int
err = rows.Scan(&test, &test2)
if err != nil {
   t.Fatal(err)
}
if test != 123 {
   t.Fatal("test != 123;", test)
}
if test2 != 456 {
   t.Fatal("test2 != 456;", test2)
}

And what I'm doing in Query is:

而我在Query中所做的是:

func (stmt *cypherStmt) Query(args []driver.Value) (driver.Rows, error) {
   cyphReq := cypherRequest{
      Query: stmt.query,
   }
   if len(args) > 0 {
      cyphReq.Params = make(map[string]interface{})
   }
   for idx, e := range args {
      cyphReq.Params[strconv.Itoa(idx)] = e
   }
...

3 个解决方案

#1


1  

It would be possible to create a map[string]interface{} type that implements driver.Valuer{} to serialize it as a []byte, and then convert it back in the driver.

可以创建一个map [string] interface {}类型,实现driver.Valuer {}将其序列化为[]字节,然后在驱动程序中将其转换回来。

But that would be inefficient and unidiomatic. Since your driver would then be used in a nonstandard way anyway, it would probably be better to just forget about database/sql and write a package with a totally custom interface.

但那将是低效和单一的。既然你的驱动程序无论如何都会以非标准的方式使用,那么忘记数据库/ sql并编写一个带有完全自定义接口的包可能会更好。

#2


8  

I'm using wrapper on top of database/sql called sqlx https://github.com/jmoiron/sqlx You can check here how he did it.

我在数据库/ sql上使用包装器,名为sqlx https://github.com/jmoiron/sqlx你可以在这里查看他是如何做到的。

Example on how to select into a tuple

关于如何选择元组的示例

type Person struct {
    FirstName string `db:"first_name"`
    LastName  string `db:"last_name"`
    Email     string
}
jason = Person{}
err = db.Get(&jason, "SELECT * FROM person WHERE first_name=$1", "Jason")
fmt.Printf("%#v\n", jason)
// Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"}

Example on how to insert a tuple

有关如何插入元组的示例

dude := Person{
    FirstName:"Jason", 
    LastName:"Moiron", 
    Email:"jmoiron@jmoiron.net"
}
 _, err = db.NamedExec(`INSERT INTO person (first_name,last_name,email) VALUES (:first,:last,:email)`, dude)

#3


4  

As far as I know, no driver natively provides for named parameters. I personally use gorp which allows you to bind queries from structs or maps:

据我所知,没有驱动程序本身提供命名参数。我个人使用gorp,它允许你绑定结构或地图的查询:

_, err = dbm.Select(&users,
    "select * from PersistentUser where mykey = :Key",
    map[string]interface{}{
        "Key": 43,
    }
)

or

要么

_, err = dbm.Select(&users,
    "select * from PersistentUser where mykey = :Key",
    User{Key: 43},
)

#1


1  

It would be possible to create a map[string]interface{} type that implements driver.Valuer{} to serialize it as a []byte, and then convert it back in the driver.

可以创建一个map [string] interface {}类型,实现driver.Valuer {}将其序列化为[]字节,然后在驱动程序中将其转换回来。

But that would be inefficient and unidiomatic. Since your driver would then be used in a nonstandard way anyway, it would probably be better to just forget about database/sql and write a package with a totally custom interface.

但那将是低效和单一的。既然你的驱动程序无论如何都会以非标准的方式使用,那么忘记数据库/ sql并编写一个带有完全自定义接口的包可能会更好。

#2


8  

I'm using wrapper on top of database/sql called sqlx https://github.com/jmoiron/sqlx You can check here how he did it.

我在数据库/ sql上使用包装器,名为sqlx https://github.com/jmoiron/sqlx你可以在这里查看他是如何做到的。

Example on how to select into a tuple

关于如何选择元组的示例

type Person struct {
    FirstName string `db:"first_name"`
    LastName  string `db:"last_name"`
    Email     string
}
jason = Person{}
err = db.Get(&jason, "SELECT * FROM person WHERE first_name=$1", "Jason")
fmt.Printf("%#v\n", jason)
// Person{FirstName:"Jason", LastName:"Moiron", Email:"jmoiron@jmoiron.net"}

Example on how to insert a tuple

有关如何插入元组的示例

dude := Person{
    FirstName:"Jason", 
    LastName:"Moiron", 
    Email:"jmoiron@jmoiron.net"
}
 _, err = db.NamedExec(`INSERT INTO person (first_name,last_name,email) VALUES (:first,:last,:email)`, dude)

#3


4  

As far as I know, no driver natively provides for named parameters. I personally use gorp which allows you to bind queries from structs or maps:

据我所知,没有驱动程序本身提供命名参数。我个人使用gorp,它允许你绑定结构或地图的查询:

_, err = dbm.Select(&users,
    "select * from PersistentUser where mykey = :Key",
    map[string]interface{}{
        "Key": 43,
    }
)

or

要么

_, err = dbm.Select(&users,
    "select * from PersistentUser where mykey = :Key",
    User{Key: 43},
)