目录


连接数据库

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)
}
}