面试题答案
一键面试通用方法
- 使用参数化查询:在构建SQL语句时,使用占位符代替直接拼接用户输入的值。不同数据库的占位符形式可能不同,如MySQL使用
?
,SQLite也常用?
。database/sql
包会自动处理参数值的转义和类型匹配,有效防止SQL注入。 - 输入验证和过滤:在接收用户输入后,对其进行验证,确保输入符合预期的格式和范围。例如,用户名通常只包含字母、数字等合法字符。虽然这不能完全替代参数化查询,但能进一步增强安全性。
MySQL特殊注意点
- 占位符使用:MySQL在
database/sql
包中使用?
作为占位符。 - 驱动版本:确保使用的MySQL驱动版本是最新且稳定的,以获取最新的安全修复和特性。
SQLite特殊注意点
- 占位符使用:SQLite同样常用
?
作为占位符,但某些情况下也支持$name
这种具名占位符形式。 - 事务处理:SQLite对事务支持较好,在进行复杂操作时,合理使用事务能保证数据的一致性和完整性。
代码示例
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql" // 假设使用MySQL,需导入对应驱动
)
func main() {
// 数据库连接
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/yourdatabase")
if err != nil {
panic(err.Error())
}
defer db.Close()
// 用户输入
username := "testuser"
password := "testpassword"
var count int
err = db.QueryRow("SELECT COUNT(*) FROM users WHERE username =? AND password =?", username, password).Scan(&count)
if err != nil {
fmt.Println("查询错误:", err)
return
}
if count > 0 {
fmt.Println("用户存在")
} else {
fmt.Println("用户不存在")
}
}
若使用SQLite,导入SQLite驱动(如_ "github.com/mattn/go - sqlite3"
),并修改连接字符串,如下:
package main
import (
"database/sql"
"fmt"
_ "github.com/mattn/go - sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "test.db")
if err != nil {
panic(err.Error())
}
defer db.Close()
username := "testuser"
password := "testpassword"
var count int
err = db.QueryRow("SELECT COUNT(*) FROM users WHERE username =? AND password =?", username, password).Scan(&count)
if err != nil {
fmt.Println("查询错误:", err)
return
}
if count > 0 {
fmt.Println("用户存在")
} else {
fmt.Println("用户不存在")
}
}