• Go语言操作MySQL数据库


    7,Go操作MySQl

    1.依赖下载

    go get -u github.com/go-sql-driver/mysql
    
    • 通过函数,驱动mysql
    func Open(driverName, dataSourceName string) (*DB error)
    
    • 示例,打开一个SQL连接
    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下面。
    }
    

    2.连接的初始化

    • 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
      ", err)
      		return
      	}
      }
      
    • Sql.DB 表示连接数据库对象(结构体实例)。它内部维护着一个具有零到多个底层连接的连接池,它可以安全地被多个goroutine同时使用。

    3.SetMaxOpenConns

    • SetMaxOpenConns设置与数据库建立连接的最大数目。如果n大雨0且小于最大闲置连接数,会将最大闲置连接数减小到匹配最大开启连接数的限制。 如果n<=0,不会限制最大开启连接数,默认为0(无限制)

      func (db *DB) SetMaxOpenConns(n int)
      

    4.SetMaxIdleConns

    • SetMaxIdleConns设置连接池中的最大闲置连接数。 如果n大于最大开启连接数,则新的最大闲置连接数会减小到匹配最大开启连接数的限制。 如果n<=0,不会保留闲置连接。

      func (db *DB) SetMaxIdleConns(n int)
      

    5.CURD boy

    5.1 插入数据

    • 插入,更新和删除操作使用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
      ", err)
      	}
      	// 获取新数据插入id
      	theID, err := ret.LastInsertId()
      	if err != nil {
      		fmt.Printf("get last insert IO failed, err:%v
      ", err)
      		return
      	}
      	fmt.Printf("insert success, the id is %d.
      ",theID)
      }
      // insert success, the id is 1.
      

    5.2 更新操作

    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
    ",err)
    		return
    	}
    	n, err := ret.RowsAffected() //获取操作影响的行数
    	if err!= nil {
    		fmt.Printf("get RowsAffected failed err:%v
    ",err)
    		return
    	}
    	fmt.Printf("update success affected rows:%d
    ",n)
    }
    // update success affected rows:1
    

    5.3 删除操作

    func deleteRowDemo() {
    	sqlStr := "delete from user where id=?"
    	ret, err := db.Exec(sqlStr,3)
    	if err != nil {
    		fmt.Printf("delete failed, err:%v
    ", err)
    		return
    	}
    	n, err := ret.RowsAffected() //操作影响的行数
    	if err!=nil{
    		fmt.Printf("get RowAffected failed, err:%v
    ",err)
    		return
    	}
    	fmt.Printf("delete success, affected rows:%d
    ", n)
    }
    

    5.4单行数据查询

    • 单行查询通过:db.QueryRow().
    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
    ",err)
    		return
    	}
    	fmt.Printf("id:%d name:%s age:%d",u.id,u.name,u.age)//id:1 name:小明 age:25
    }
    

    5.5多行查询

    • 多行查询db.Query() 执行一次查询。返回多行结果。一般用于执行select命令,参数 args表示query中的占位参数。
    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
    ",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
    ", err)
    			return
    		}
    		fmt.Printf("id:%d name:%s age:%d
    ", u.id, u.name, u.age)
    	}
    }
    

    6.MySQL预处理

    6.1什么是预处理?

    • 普通SQL执行:

      • 客户端对SQL语句进行占位符替换得到完整的SQL语句。
      • 客户端发送完整SQL语句到MySQL服务端。
      • MySQL服务端执行完整的SQL语句并将结果返回给客户端。
    • 预处理执行过程:

      • 把SQL语句分成两部分,命令部分与数据部分。
      • 先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预处理。
      • 然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位替换。
      • MySQL服务端执行完整的SQL语句并将结果返回给客户端。

    6.2预处理好处

    • 避免SQL注入问题。
    • 优化MySQL服务器重复执行SQL的方法,可以提升服务器性能,提前让服务器编译,一次编译多次执行,节省后续编译成本。

    6.3预处理示例

    • 查询操作的预处理示例代码如下:

      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
      ", err)
      		return
      	}
      	defer stmt.Close()
      	// 数据部分发送MySQL服务端。
      	rows, err := stmt.Query(0)
      	if err != nil {
      		fmt.Printf("query failed err:%v
      ",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
      ", err)
      			return
      		}
      		fmt.Printf("id:%d name:%s age:%d
      ", 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
      ", err)
      	}
      	defer stmt.Close()
      	// 添加数据
      	_, err = stmt.Exec("小红", 18)
      	if err != nil {
      		fmt.Printf("insert failed, err:%v
      ", err)
      		return
      	}
      	_, err = stmt.Exec("李二",25)
      	if err != nil {
      		fmt.Printf("insert failed err:%v
      ", err)
      	}
      	fmt.Println("insert success!")
      }
      

    6.4数据库占位符

    数据库 占位符语法
    MySQL ?
    PostgreSQL $1, $2等
    SQLite ?和$1
    Oracle :name

    7.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:%v
      ",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
      ",err)
      		return
      	}
      	// 获取更改行数
      	affRow1, err := ret1.RowsAffected()
      	if err != nil {
      		fmt.Printf("exec ret1.RowsAffected() failed, err:%v
      ",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
      ", err)
      		return
      	}
      	affRow2, err := ret2.RowsAffected()
      	if err != nil {
      		tx.Rollback()
      		fmt.Printf("exec ret2.RowsAffected() failed,Err:%v
      ", 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.liwenzhou.com/posts/Go/go_mysql/

  • 相关阅读:
    mariadb
    Linux下安装配置virtualenv与virtualenvwrapper
    配置安装源
    Redis哨兵
    Android 常用工具类之DeviceInfoUtil
    Android 常用工具类之RuntimeUtil
    android 中的几种目录
    listview 滑动以后设置最上面一行为整行展示
    Android 常用工具类之SPUtil,可以修改默认sp文件的路径
    android 在应用中切换语言
  • 原文地址:https://www.cnblogs.com/xujunkai/p/13369225.html
Copyright © 2020-2023  润新知