我见过两种人使用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")
}
第一个使您能够动态设置表名,列名和值,从而获益。但第二个只针对价值观。有什么不同?我应该使用哪一个?
答案 0 :(得分:3)
从不从来自系统外部的字符串构建SQL。
始终使用nil
语法。
如果必须设置SQL部分(如表名),请准备多个包含值?
的完整SQL语句。选择要执行的SQL,可能基于用户输入,但从不从用户输入构建SQL 。
答案 1 :(得分:1)
使用预准备语句更加清晰,这样每当需求发生变化时,您都可以轻松修改语句。还要防止SQL注入。
准备好的语句比连接字符串要好得多 通常的原因(例如,避免SQL注入攻击)。
在MySQL中,参数占位符是?,而在PostgreSQL中它是$ N, 其中N是数字。 SQLite接受其中任何一个。
还有一件事是Prepared语句可以用于重复方法,可以多次执行并且可以被销毁。
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