go get -u github.com/go-sql-driver/mysql
func Open(driverName, dataSourceName string) (*DB error)
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
func main() {
// user 用户名
// password 密码
// host IP
// port 端口
// dbName 库名
dsn := "user:password@tcp(host:port)/dbName"
db, err := sql.Open("mysql",dsn)
if err != nil{
panic(err)
}
defer db.Close()// 这里写在err下面。
}
Open函数可能只是验证其参互格式是否正确,实际上并不创建与数据库的连接,如果要检查数据源的名称是否真实有效应该调用ping
返回DB对象可以被多个goroutine并发使用,并且维护其自己的空闲连接池。因此Open函数应该仅被调用一次,很少需要关闭这个DB对象。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
// 全局定义db对象
var db *sql.DB
func initDB() (err error) {
dsn := "root:123@tcp(IP:HOST)/user_list?charset=utf8mb4&parseTime=True"
// 注意!!!这里不要使用:=,我们是给全局变量赋值,然后在main函数中使用全局变量db
db, err = sql.Open("mysql",dsn)
if err != nil{
return err
}
// 尝试与数据库建立连接(校验dsn是否正确)
err = db.Ping()
if err != nil{
return err
}
return nil
}
func main() {
err := initDB()
if err != nil {
fmt.Printf("init db failed, err:%v\n", err)
return
}
}
Sql.DB 表示连接数据库对象(结构体实例)。它内部维护着一个具有零到多个底层连接的连接池,它可以安全地被多个goroutine同时使用。
SetMaxOpenConns设置与数据库建立连接的最大数目。如果n大雨0且小于最大闲置连接数,会将最大闲置连接数减小到匹配最大开启连接数的限制。 如果n<=0,不会限制最大开启连接数,默认为0(无限制)
func (db *DB) SetMaxOpenConns(n int)
SetMaxIdleConns设置连接池中的最大闲置连接数。 如果n大于最大开启连接数,则新的最大闲置连接数会减小到匹配最大开启连接数的限制。 如果n<=0,不会保留闲置连接。
func (db *DB) SetMaxIdleConns(n int)
插入,更新和删除操作使用Exec方法。
func (db *DB) Exec(query string, args ...interface{}) (Result, error)
操作:
var db *sql.DB
func inserRowDemo() {
sqlStr := "insert into user(name,age) values (?,?)"
ret, err := db.Exec(sqlStr,"小明",25)
if err != nil {
fmt.Printf("insert failed, err:%v\n", err)
}
// 获取新数据插入id
theID, err := ret.LastInsertId()
if err != nil {
fmt.Printf("get last insert IO failed, err:%v\n", err)
return
}
fmt.Printf("insert success, the id is %d.\n",theID)
}
// insert success, the id is 1.
func updateRowDemo() {
sqlStr := "update user set age=? where id=?"
ret,err := db.Exec(sqlStr,35,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)
}
// update success affected rows:1
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 RowAffected failed, err:%v\n",err)
return
}
fmt.Printf("delete success, affected rows:%d\n", n)
}
func (db *DB) QueryRow(query string, args ...interface{}) *Row
type user struct {
id int
age int
name string
}
func queryRowDemo(){
sqlStr := "select id,name,age from user where id=?"
var u user
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",u.id,u.name,u.age)//id:1 name:小明 age:25
}
func (db *DB) Query(query string, args ...interface{}) (*Rows, error)
type user struct {
id int
age int
name string
}
func queryMultiRowDemo(){
sqlStr := "select id,name,age from user 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.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)
}
}
普通SQL执行:
预处理执行过程:
查询操作的预处理示例代码如下:
func prepareQueryDemo() {
sqlStr := "select id,name,age from user where id > ?"
// 预处理一条SQL语句
stmt, err := db.Prepare(sqlStr)
if err != nil {
fmt.Printf("prepare failed,err:%v\n", err)
return
}
defer stmt.Close()
// 数据部分发送MySQL服务端。
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)
}
}
插入消息预处理示例
func preporeInsertDemo() {
sqlStr := "insert into user(name,age) values(?,?)"
// 预处理一条SQL语句
stmt, err := db.Prepare(sqlStr)
if err != nil {
fmt.Printf("prepare failed, err:%v\n", err)
}
defer stmt.Close()
// 添加数据
_, err = stmt.Exec("小红", 18)
if err != nil {
fmt.Printf("insert failed, err:%v\n", err)
return
}
_, err = stmt.Exec("李二",25)
if err != nil {
fmt.Printf("insert failed err:%v\n", err)
}
fmt.Println("insert success!")
}
数据库 | 占位符语法 |
---|---|
MySQL | ? |
PostgreSQL | $1, $2等 |
SQLite | ?和$1 |
Oracle | :name |
事务具有四大特性:原子性,一致性,隔离性,持久性。
事务相关语法:
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:%v\n",err)
return
}
sqlStrl := "Update user set age=18 where id=?"
ret1, err := tx.Exec(sqlStrl,1)
if err != nil {
tx.Rollback()
fmt.Printf("exec sql1 failed, err:%v\n",err)
return
}
// 获取更改行数
affRow1, err := ret1.RowsAffected()
if err != nil {
fmt.Printf("exec ret1.RowsAffected() failed, err:%v\n",err)
return
}
sqlStr2 := "Update user set age=22 where id=?"
ret2, err := tx.Exec(sqlStr2, 4)
if err != nil{
tx.Rollback()//回滚
fmt.Printf("exec sql2 failed, err:%v\n", err)
return
}
affRow2, err := ret2.RowsAffected()
if err != nil {
tx.Rollback()
fmt.Printf("exec ret2.RowsAffected() failed,Err:%v\n", 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!")
}
原文:https://www.cnblogs.com/xujunkai/p/13369225.html