Golang中MYSQL驱动
Mysql库https://github.com/go-sql-driver/mysql
Go本身不提供具体数据库驱动,只提供驱动接口和管理。
各个数据库驱动需要第三方实现,并且注册到Go中的驱动管理中。
安装golang mysql drvier
go get github.com/go-sql-driver/mysql
代码中需要注册mysql数据库驱动,通过引入空白导入mysql包来完成。
为什么需要使用空白导入? 是因为需要执行mysql包的初始化代码(代码位于%GOPATH%/github.com/go-sql-driver/mysql/driver.go)
func init() {
sql.Register("mysql", &MySQLDriver{})
}
连接数据的DSN格式
username:password@protocol(address)/dbname?param=value
Prepared Statement
sql.Stmt支持预备表达式,可以用来优化SQL查询提高性能,减少SQL注入的风险, DB.Prepare()和Tx.Prepare()都提供了对于预备表达式的支持。
预处理的流程:
step1. 将sql分为2部分.命令部分和数据部分.
step2. 首先将命令部分发送给mysql服务器,mysql进行预处理.(如生成AST)
step3. 然后将数据部分发送给mysql服务器,mysql进行占位符替换.
step4. mysql服务器执行sql语句,把执行结果发送给客户端.
预处理的优势:
1.因为发送命令后,在mysql服务器端,就会将AST生成好,所以不需要对每一次值的更换都重新生成一次AST.对同样的数据不同的SQL来讲,只需生成1次AST,并缓存起来即可.
2.避免SQL注入.因为mysql知道再次发送过来的内容为”数据”,因此不会将这些数据解析为SQL,避免了SQL注入.
需要注意的点:
使用预处理进行查询操作时,不仅在defer时需要关闭结果集,而且还要关闭命令句柄,否则同样会占用连接,导致阻塞.
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt"
)
type User struct {
Id int `db:"id"`
Name string `db:"name"`
Age int `db:"age"`
}
func PrepareQuery(db *sql.DB, id int) {
stmt, err := db.Prepare("select id, name, age from user where id>?")
if err != nil {
panic(err)
}
rows, err := stmt.Query(id)
if err != nil {
panic(err)
}
defer stmt.Close()
defer rows.Close()
for rows.Next(){
var user User
err := rows.Scan(&user.Id, &user.Name, &user.Age)
if err != nil {
panic(err)
}
fmt.Printf("user: %#v\n", user)
}
}
func main() {
dns := "root:123456@tcp(172.16.65.200:3306)/golang"
db, err := sql.Open("mysql", dns)
if err != nil {
panic(err)
}
defer db.Close()
PrepareQuery(db, 0)
}
Mysql创建表:
CREATE TABLE user (
id int(20) NOT NULL AUTO_INCREMENT,
name varchar(20) DEFAULT '',
age int(2) DEFAULT '0',
PRIMARY KEY (id))
ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
数据库增删改查
insert
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt"
)
func Insert(db *sql.DB) {
name := "Vincent"
age := 18
result, err := db.Exec("insert into user(name, age) values (?,?)", name, age)
if err != nil {
panic(err)
}
id, err := result.LastInsertId()
if err != nil {
panic(err)
}
affected, err := result.RowsAffected()
if err != nil {
panic(err)
}
fmt.Printf("last insert id:%d affect rows:%d\n", id, affected)
}
func main() {
dns := "root:123456@tcp(172.16.65.200