在 Golang 中执行 SQL 查询

Executing SQL query in Golang

我见过人们使用 Golang 内置 database/sql 查询执行查询的两种方式。其中之一是使用 fmt.Sprintf:

func (db *DB) CreateUserTable() (sql.Result, error) {
    statement := "CREATE TABLE %s (%s, %s, %s, %s, %s)"
    v := []interface{}{"User", "ID int PRIMARY KEY NOT NULL", "Name varchar(100) UNIQUE", "Email varchar(100) UNIQUE", "Address varchar(100) ",  "Username varchar(100) UNIQUE"}
    return db.Exec(fmt.Sprintf(statement, v...))
}

另一个是使用预处理语句:

func (db *DB) CreateUserTable() (sql.Result, error) {    
    statement, err := db.Prepare("INSERT INTO User(tbl1,tbl2,tbl3) VALUES(?,?,?)")
    if err != nil {
        log.Fatal(err)
    }
    return statement.Exec("value1", "value2", "value3")
}

第一个好处是使您能够动态设置 table 名称、列名称和值。但是第二个仅用于值。有什么不同?我应该使用哪一个?

从不 从来自系统外部的字符串构建 SQL。

始终 使用 ? 语法。

如果您必须设置 SQL 部分,例如 table 名称,请准备多个包含 ? 值的完整 SQL 语句。 Select SQL 执行,可能基于用户输入,但 never build SQL from user输入。

使用准备好的语句更简洁,这样只要需求发生变化,您就可以轻松修改语句。也为了防止 SQL 注入。

Prepared statements is much better than concatenating strings, for all the usual reasons (avoiding SQL injection attacks, for example).

In MySQL, the parameter placeholder is ?, and in PostgreSQL it is $N, where N is a number. SQLite accepts either of these.

还有一点是Prepared statements可以用于重复的方法,可以执行多次,也可以销毁。

stmt, err := db.Prepare("select id, name from users where id = ?")
if err != nil {
    log.Fatal(err)
}
defer stmt.Close() // closing the statement
rows, err := stmt.Query(1)

并且您正在使用接口

func (db *DB) CreateUserTable() (sql.Result, error) {
    statement := "CREATE TABLE %s (%s, %s, %s, %s, %s)"
    v := []interface{}{"User", "ID int PRIMARY KEY NOT NULL", "Name varchar(100) UNIQUE", "Email varchar(100) UNIQUE", "Address varchar(100) ",  "Username varchar(100) UNIQUE"}
    return db.Exec(fmt.Sprintf(statement, v...))
}

它可以在幕后采用任何类型的参数,这很容易受到攻击

要了解更多详细信息,请执行此操作Link