安装mysql驱动:
go get -u github.com/go-sql-driver/mysql
初始化模块
go mod init m
执行
go mod tidy
导入包:
package main import ( "fmt" "database/sql" _ "github.com/go-sql-driver/mysql" )
获得链接:
package main import ( "database/sql" _ "github.com/go-sql-driver/mysql" "time" ) func main() { db, err := sql.Open("mysql", "root:123456@/go_db") if err != nil { panic(err) } print(db) // 最大连接时长 db.SetConnMaxLifetime(time.Minute * 3) // 最大连接数 db.SetMaxOpenConns(10) // 空闲连接数 db.SetMaxIdleConns(10) }
初始化连接
Open函数可能只是验证其参数格式是否正确,实际上并不创建与数据库的连接。如果要检查数据源的名称是否真实有效,应该调用Ping方法。
返回的DB对象可以安全地被多个goroutine并发使用,并且维护其自己的空闲连接池。因此,Open函数应该仅被调用一次,很少需要关闭这个DB对象。
package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" ) // 定义一个全局对象db var db2 *sql.DB // 定义一个初始化数据库的函数 func initDB() (err error) { dsn := "root:123456@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True" // 不会校验账号密码是否正确 // 注意!!!这里不要使用:=,我们是给全局变量赋值,然后在main函数中使用全局变量db db2, err = sql.Open("mysql", dsn) if err != nil { return err } // 尝试与数据库建立连接(校验dsn是否正确) err = db2.Ping() if err != nil { return err } return nil } func main() { err := initDB() // 调用输出化数据库的函数 if err != nil { fmt.Printf("初始化失败!,err:%v\n", err) return }else{ fmt.Printf("初始化成功") } }
当行查询:
单行查询db.QueryRow()
执行一次查询,并期望返回最多一行结果(即Row)。QueryRow总是返回非nil的值,直到返回值的Scan方法被调用时,才会返回被延迟的错误。
定义结构体:
type user struct { id int username string password string }
// 查询一条用户数据 func queryRowDemo() { sqlStr := "select id, username, password from user_tbl where id=?" var u user // 确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放 err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.username, &u.password) if err != nil { fmt.Printf("scan failed, err:%v\n", err) return } fmt.Printf("id:%d name:%s age:%s\n", u.id, u.username, u.password) }
func main() { err := initDB() // 调用输出化数据库的函数 if err != nil { fmt.Printf("初始化失败!,err:%v\n", err) return }else{ fmt.Printf("初始化成功") } queryRowDemo() }
查询多行
多行查询db.Query()
执行一次查询,返回多行结果(即Rows),一般用于执行select命令。参数args表示query中的占位参数。
// 查询多条数据示例 func queryMultiRow() { sqlStr := "select id, username, password from user_tbl where id > ?" rows, err := db.Query(sqlStr, 0) if err != nil { fmt.Printf("query failed, err:%v\n", err) return } // 非常重要:关闭rows释放持有的数据库链接 defer rows.Close() // 循环读取结果集中的数据 for rows.Next() { var u user err := rows.Scan(&u.id, &u.username, &u.password) if err != nil { fmt.Printf("scan failed, err:%v\n", err) return } fmt.Printf("id:%d username:%s password:%s\n", u.id, u.username, u.password) } }
插入,更新和删除操作都使用Exec方法
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
新增: // 插入数据 func insertData() { sqlStr := "insert into user_tbl(username,password) values (?,?)" ret, err := db.Exec(sqlStr, "张三", "zs123") 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 delData() { sql := "delete from user_tbl where id =?" ret, err := db.Exec(sql, "1") if err != nil { fmt.Printf("删除失败, err:%v\n", err) return } rows, err := ret.RowsAffected() if err != nil { fmt.Printf("删除行失败, err:%v\n", err) return } fmt.Printf("删除成功, 删除的行数:%d.\n", rows) } 更新: func updateData() { sql := "update user_tbl set username=?, password=? where id=?" ret, err := db.Exec(sql, "kite2", "kite123", "2") if err != nil { fmt.Printf("更新失败, err:%v\n", err) return } rows, err := ret.RowsAffected() if err != nil { fmt.Printf("更新行失败, err:%v\n", err) return } fmt.Printf("更新成功, 更新的行数:%d.\n", rows) }
注意点:
1.表名不能作为占位符使用
"DELETE FROM `?` WHERE created_date BETWEEN ? AND ?" ret, err := db3.Exec(sql, tableName, startDate, endDate)
2.dsn中用户名和密码 如果包含特殊字符:!@#^*等,需要进行urlencode处理
url.QueryEscape