go语言中的database/sql包提供了Sql数据库的泛用接口,但是不提供具体的驱动。使用这个包时必须注入数据库驱动。
下载依赖go get -u github.com/go-sql-driver/mysql使用MySql驱动
func Open(driverName, dataSourceName string) (*DB, error)
打开一个指定driverName的数据库,dataSourceName指定数据源
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func Open() {
// DSN:data source name
dsn := "root:123@tcp(127.0.0.1:3306)/t1231est"
db, err := sql.Open("mysql", dsn)
if err != nil {
fmt.Printf("打开失败,db:%#v", db)
panic(err)
}
defer db.Close() // 写在error判断的下面
fmt.Printf("成功打开数据库,db:%#v", db)
}
初始化连接
Open函数只有检查参数格式的作用,并不创建与数据库的连接,如需检查数据源是否有效应该使用Ping方法。
Open得到的DB对象可以被多个goroutine并发使用,并且维护一个空闲的连接池。所以Open函数应该只被调用一次,很少关闭DB对象。
// 定义一个全局变量
var db *sql.DB // 表示连接的数据库对象, 内部维护着一个连接池,可以安全的被多个goroutine使用
func initDB() (err error) {
dsn := "root:123@tcp(127.0.0.1:3306)/tes22t"
db, err = sql.Open("mysql", dsn)
if err != nil {
fmt.Printf("打开失败,db:%#v", db)
return err
}
// 尝试与数据库建立连接
err = db.Ping()
if err != nil {
return err
}
return nil
}
SetMaxOpenConns
func (db *DB) SetMaxOpenConns(n int)
设置与数据库建立连接的最大数目。n≤0时连接数无限制,0 设置连接池中的最大闲置连接数。n ≤ 0时不会保留闲置连接,n > 最大开启连接数时,最大闲置连接数减小到最大开启连接数。 选定或新建一个数据库,使用以下SQL创建一张表 首先封装结构体代表表中的每一行记录 通过db.QueryRow()来查询单行数据,期望返回最多一行结果。 返回值的Scan方法被调用时才会返回被延时的错误。 示例: db.Query()执行一次查询返回多行数据 示例: 插入、更新和删除操作都使用Exec方法。 Result是对已执行的SQL命令的总结, 参数args表示query中的占位参数。 示例: 不使用预处理时完整的SQL语句会发送给客户端,会有SQL注入的风险。使用预处理可以将SQL与数据拆分,先将要执行的SQL“模板”发送给数据库预处理,之后再将占位符参数发送给数据库,这样就可以防止SQL注入。 普通SQL语句执行过程: 预处理执行过程: database/sql中使用下面的Prepare方法来实现预处理操作。 返回值可以同时执行多个查询和命令。 查询示例: 插入、删除、更新示例: 开启事务 提交事务 回滚事务func (db *DB) SetMaxIdleConns(n int)
CREATE TABLE `user` (
`id` int(4) NOT NULL,
`name` varchar(32) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
查询
// 创建结构体封装数据库查询对象
type user struct {
id int
name string
}
单行查询
func (db *DB) QueryRow(query string, args ...interface{}) *Row
func queryRowDemo() {
sqlStr := "select id, name from user where id = ?"
var u user
// 确保QueryRow之后调用Scan方法,否则持有的数据库连接不会被释放
err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.name)
if err != nil {
fmt.Printf("scan failed, err:%vn", err)
return
}
fmt.Printf("id:%d name:%sn", u.id, u.name)
}
多行查询
func (db *DB) Query(query string, args ...interface{}) (*Rows, error)
func queryMultiRowDemo() {
sqlStr := "select id, name from user where id > 0"
rows, err := db.Query(sqlStr)
if err != nil {
fmt.Printf("scan failed, err:%vn", err)
return
}
// 非常重要,关闭rows释放所有连接数据
defer rows.Close()
// 循环读取结果集中的数据
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name)
if err != nil {
fmt.Printf("Scan failed ,err: %vn", err)
return
}
fmt.Printf("id:%d name:%sn", u.id, u.name)
}
}
插入
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
func insertRowDemo() {
sqlstr := "insert into user (id, name) values (?, ?)"
ret, err := db.Exec(sqlstr, 223, "王五")
if err != nil {
fmt.Printf("insert failed, err:%vn", err)
return
}
theID, err := ret.LastInsertId()
if err != nil {
fmt.Printf("get lastinsert ID failed, err:%vn", err)
return
}
fmt.Printf("insert success, the id is %d.n", theID)
}
更新
func updateRowDemo() {
sqlStr := "update user set name = ? where id = ?"
ret, err := db.Exec(sqlStr, "张s", 222)
if err != nil {
fmt.Printf("update failed, err:%vn", err)
return
}
n, err := ret.RowsAffected()
if err != nil {
fmt.Printf("get RowsAffected failed, err:%vn", err)
return
}
fmt.Printf("update success, affected rows:%dn", n)
}
删除
func deleteRowDemo() {
sqlstr := "delete from user where id = ?"
ret, err := db.Exec(sqlstr, 2)
if err != nil {
fmt.Printf("delete failed, err:%vn", err)
return
}
n, err := ret.RowsAffected()
if err != nil {
fmt.Printf("get RowsAffected failed, err:%vn", err)
return
}
fmt.Printf("delete success, affected rows:%dn", n)
}
预处理
概念
优点
Go实现MySql预处理语句
func (db *DB) Prepare(query string) (*Stmt, error)
func prepareQueryDemo() {
sqlstr := "select id, name from user where id > ?"
s, err := db.Prepare(sqlstr)
if err != nil {
fmt.Printf("prepare failed, err:%v", err)
return
}
defer s.Close()
rows, err := s.Query(0)
if err != nil {
fmt.Printf("query failed, err:%vn", err)
return
}
defer rows.Close()
for rows.Next() {
var u user
err := rows.Scan(&u.id, &u.name)
if err != nil {
fmt.Printf("scan failed, err:%vn", err)
return
}
fmt.Printf("id:%d name:%sn", u.id, u.name)
}
}
func prepareInsertDemo() {
sqlStr := "insert into user (id, name) values (?, ?)"
s, err := db.Prepare(sqlStr)
if err != nil {
fmt.Printf("prepare failed err:%v", err)
return
}
defer s.Close()
_, err = s.Exec(123, "大王子")
if err != nil {
fmt.Printf("insert failed err:%v", err)
return
}
_, err = s.Exec(124, "小公主")
if err != nil {
fmt.Printf("insert failed err:%v", err)
return
}
fmt.Printf("insert succeed")
}
Go实现MySql事务
func (db *DB) Begin() (*Tx, error)
func (tx *Tx) Commit() error
func (tx *Tx) Rollback() error
示例
func transactionDemo() {
tx, err := db.Begin() // 开启一个事务
if err != nil {
if tx != nil {
tx.Rollback()
}
fmt.Printf("begin trans failed , err:%vn", err)
return
}
sqlStr1 := "Update user set name = ? where id = ?"
ret1, err := tx.Exec(sqlStr1, "大公主", 124)
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec sql1 failed, err:%vn", err)
return
}
affRow1, err := ret1.RowsAffected()
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec ret1.RowsAffected() failed, err:%vn", err)
return
}
sqlStr2 := "Update user set name='王大锤' where id=?"
ret2, err := tx.Exec(sqlStr2, 3)
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec sql2 failed, err:%vn", err)
return
}
affRow2, err := ret2.RowsAffected()
if err != nil {
tx.Rollback() // 回滚
fmt.Printf("exec ret1.RowsAffected() failed, err:%vn", err)
return
}
fmt.Println(affRow1, affRow2)
if affRow1 == 1 && affRow2 == 1 {
fmt.Println("事务提交啦...")
tx.Commit() // 提交事务
} else {
tx.Rollback()
fmt.Println("事务回滚啦...")
}
fmt.Println("exec trans success!")
}



