Go的database/sql体验篇
Go官方提供了database/sql接口用于数据库交互,但其实database/sql库只是提供了一套接口和规范,比如大家熟悉的SQL预处理、连接池、数据绑定、事务、错误处理等。本篇为实际操作篇
简单来说这个包提供了sql的泛用接口,使用时还要注入一个数据库驱动
导入driver
import (
"database/sql" //官方sql包
_ "github.com/go-sql-driver/mysql" //一个driver的驱动
)
这里_
表示只调用mysql包中的init函数,不使用这个包里的变量和函数。
连接数据库
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
这里sql.Open第一个参数就是上面传进来的driver的名字,第二个参数分别是用户名、密码、数据库地址:端口号、对应具体的数据库
查询一条/多条数据
用Query先试试
var (
id int
name string
)
//rows, err := db.Query("select id,name from user where id = ?", 1)
rows, err := db.Query("select id, name from user")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
fmt.Println("rows: ", rows)
for rows.Next() {
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
//log.Println(id, name)
fmt.Printf("id:%d ,name: %s \n", id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
不管是一条还是多条查询都一样,拿个for循环来接收结果就行
多
插入一条数据
在mybatis里我们也有PreparedStatements的说法,用于执行insert、update、delete的操作,在这也差不多
这里嫌麻烦先把checkErr抽出来了
func checkErr(err error) {
if err != nil {
log.Fatal(err)
}
}
插入部分
func insertDB() {
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
stmt, err := db.Prepare("INSERT INTO user(id, name, pwd, perms) VALUES(?, ?, ?, ?)")
checkErr(err)
res, err := stmt.Exec(12, "Marks", "666555", "")
checkErr(err)
fmt.Println(res.LastInsertId())
//lastId, err := res.LastInsertId()
//checkErr(err)
//rowCnt, err := res.RowsAffected()
//checkErr(err)
//log.Printf("ID = %d, affected = %d\n", lastId, rowCnt)
}
运行
当然也可以直接插入,不用PreparedStatements方式
func insertDirect() {
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sql := "INSERT INTO user(id, name, pwd) VALUES(?, ?, ?)"
res, err := db.Exec(sql, 13, "Jobs", "444555")
checkErr(err)
fmt.Println(res.LastInsertId())
}
一样
删除数据
func deleteDB() {
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sql := "DELETE FROM user where id=?"
res, err := db.Exec(sql, 12)
checkErr(err)
fmt.Println(res.RowsAffected())
}
更新数据
func updateDB() {
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
sql := "UPDATE user SET name=? WHERE id=?"
stmt, err := db.Prepare(sql)
checkErr(err)
defer stmt.Close()
result, err := stmt.Exec("Marksss", 12)
checkErr(err)
fmt.Println(result.RowsAffected())
}
修改成功没问题
事务支持
完成一系列的操作可以用事务的格式
func transDB() {
db, err := sql.Open("mysql",
"username:password@tcp(127.0.0.1:3306)/test_db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
tx, err := db.Begin()
checkErr(err)
_, err = tx.Exec("UPDATE user SET pwd = ? WHERE id = ?", "888999", 10)
checkTxErr(err, tx)
_, err = tx.Exec("UPDATE user SET pwd = ? WHERE id = ?", "888999", 11)
checkTxErr(err, tx)
err = tx.Commit()
checkTxErr(err, tx)
}
func checkTxErr(err error, tx *sql.Tx) {
if err != nil {
log.Println(err)
err = tx.Rollback()
checkErr(err)
}
}
运行也没啥问题,如果报错则会回滚