目录
- 增删改
连接数据库
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB
func initMySql() (err error) { //初始化数据库函数
dsn := "root:123456@tcp(127.0.0.1:3306)/test" //用户名:密码@连接方式(ip地址)/数据库名
db, err = sql.Open("mysql", dsn)
if err != nil {
panic(err)
}
err = db.Ping()
if err != nil{
return err
}
return nil
}
func main() {
if err := initMySql(); err!=nil{
fmt.Printf("连接数据库失败")
}
defer db.Close()
fmt.Printf("连接数据库成功")
}
创建表
CREATE TABLE `user` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) DEFAULT '',
`age` INT(11) DEFAULT '0',
PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
查询
查询单条数据
type user struct{
id int
age int
name string
}
// 查询单条数据示例
func queryRowDemo() {
sqlStr := "select id, name, age from user where id=?"
var u user
// 非常重要:确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放
err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.name, &u.age) //将数据库中的字段按顺序绑定上去
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
fmt.Printf("id:%d name:%s age:%d\n", u.id, u.name, u.age)
}
需要注意的是Scan
方法把数据库的字段一一绑定到结构体上(结构体的字段名不需要和数据库中完全一致)
err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.name, &u.age) //这里把&u.id和&u.age交换一下也不会报错
查询多行数据
使用函数Query
type user struct{
id int
age int
name string
}
// 查询单条数据示例
func queryRowDemo() {
sqlStr := "select id, name, age from user where id!=?"
var u user
// 非常重要:确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放
rows,err := db.Query(sqlStr, -1)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
defer rows.Close()
for rows.Next(){
err := rows.Scan(&u.id,&u.name,&u.age)
if err!=nil{
fmt.Printf("Scan fail,err: %v\n",err )
return
}
fmt.Printf("id:%d name:%s age:%d\n", u.id, u.name, u.age)
}
}
增删改
插入、更新和删除操作都使用Exec
方法。
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
Exec
执行一次命令(包括查询、删除、更新、插入等)
返回的Result
是对已执行的SQL
命令的总结。参数args
表示query
中的占位参数。
增加(插入)
// 插入数据
func insertRowDemo() {
sqlStr := "insert into user(name, age) values (?,?)"
ret, err := db.Exec(sqlStr, "小由纪同学", 17)
if err != nil {
fmt.Printf("insert failed, err:%v\n", err)
return
}
theID, err := ret.LastInsertId() // 新插入数据的id
if err != nil {
fmt.Printf("get lastinsert ID failed, err:%v\n", err)
return
}
fmt.Printf("insert success, the id is %d.\n", theID)
}
更新
// 更新数据
func updateRowDemo() {
sqlStr := "update user set age=? where id = ?"
ret, err := db.Exec(sqlStr, 39, 3)
if err != nil {
fmt.Printf("update failed, err:%v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("get RowsAffected failed, err:%v\n", err)
return
}
fmt.Printf("update success, affected rows:%d\n", n)
}
删除
// 删除数据
func deleteRowDemo() {
sqlStr := "delete from user where id = ?"
ret, err := db.Exec(sqlStr, 3)
if err != nil {
fmt.Printf("delete failed, err:%v\n", err)
return
}
n, err := ret.RowsAffected() // 操作影响的行数
if err != nil {
fmt.Printf("get RowsAffected failed, err:%v\n", err)
return
}
fmt.Printf("delete success, affected rows:%d\n", n)
}
Go实现MySQL预处理
预处理的好处
1.优化MySQL
服务器重复执行SQL
的方法,可以提升服务器性能.
提前让服务器编译,一次编译多次执行,节省后续编译的成本。
2.避免SQL注入问题。
查询预处理示例
// 预处理查询示例
func prepareQueryDemo() {
sqlStr := "select id, name, age from user where id > ?"
stmt, err := db.Prepare(sqlStr) //获得stmt对象,后续只需要不断替换参数就可以执行不同的sql
if err != nil {
fmt.Printf("prepare failed, err:%v\n", err)
return
}
defer stmt.Close()
rows, err := stmt.Query(0)
if err != nil {
fmt.Printf("query failed, err:%v\n", err)
return
}
defer rows.Close()
// 循环读取结果集中的数据
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name, &u.age)
if err != nil {
fmt.Printf("scan failed, err:%v\n", err)
return
}
fmt.Printf("id:%d name:%s age:%d\n", u.id, u.name, u.age)
}
}