亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語言操作MySQL的知識總結(jié)

 更新時間:2022年11月09日 11:17:34   作者:qi66  
Go語言中的database/sql包提供了保證SQL或類SQL數(shù)據(jù)庫的泛用接口,并不提供具體的數(shù)據(jù)庫驅(qū)動。本文介紹了Go語言操作MySQL的相關(guān)知識,感興趣的可以了解一下

一、連接

Go語言中的database/sql包提供了保證SQL或類SQL數(shù)據(jù)庫的泛用接口,并不提供具體的數(shù)據(jù)庫驅(qū)動。使用database/sql包時必須注入(至少)一個數(shù)據(jù)庫驅(qū)動。

我們常用的數(shù)據(jù)庫基本上都有完整的第三方實(shí)現(xiàn)。例如:MySQL驅(qū)動

1.1 下載依賴

go get -u github.com/go-sql-driver/mysql

1.2 使用MySQL驅(qū)動

func Open(driverName, dataSourceName string) (*DB, error)

Open打開一個dirverName指定的數(shù)據(jù)庫,dataSourceName指定數(shù)據(jù)源,一般至少包括數(shù)據(jù)庫文件名和其它連接必要的信息。

import (
	"database/sql"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	dsn := "user:password@tcp(127.0.0.1:3306)/dbname"
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		panic(err)
	}
	defer db.Close()  

1.3 初始化連接

返回的DB對象可以安全地被多個goroutine并發(fā)使用,并且維護(hù)其自己的空閑連接池。因此,Open函數(shù)應(yīng)該僅被調(diào)用一次,很少需要關(guān)閉這個DB對象。

接下來,我們定義一個全局變量db,用來保存數(shù)據(jù)庫連接對象。將上面的示例代碼拆分出一個獨(dú)立的initDB函數(shù),只需要在程序啟動時調(diào)用一次該函數(shù)完成全局變量db的初始化,其他函數(shù)中就可以直接使用全局變量db了。

// 定義一個全局對象db
var db *sql.DB

// 定義一個初始化數(shù)據(jù)庫的函數(shù)
func initDB() (err error) {
	// DSN:Data Source Name
	dsn := "user:password@tcp(127.0.0.1:3306)/sql_test?charset=utf8mb4&parseTime=True"
	// 注意?。。∵@里不要使用:=,我們是給全局變量賦值,然后在main函數(shù)中使用全局變量db
	db, err = sql.Open("mysql", dsn)
	if err != nil {
		return err
	}
	// 嘗試與數(shù)據(jù)庫建立連接
	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是表示連接的數(shù)據(jù)庫對象(結(jié)構(gòu)體實(shí)例),它保存了連接數(shù)據(jù)庫相關(guān)的所有信息。它內(nèi)部維護(hù)著一個具有零到多個底層連接的連接池,它可以安全地被多個goroutine同時使用。

1.4 SetMaxOpenConns

func (db *DB) SetMaxOpenConns(n int)

SetMaxOpenConns設(shè)置與數(shù)據(jù)庫建立連接的最大數(shù)目。 如果n大于0且小于最大閑置連接數(shù),會將最大閑置連接數(shù)減小到匹配最大開啟連接數(shù)的限制。 如果n<=0,不會限制最大開啟連接數(shù),默認(rèn)為0(無限制)。

1.5 SetMaxIdleConns

func (db *DB) SetMaxIdleConns(n int)

SetMaxIdleConns設(shè)置連接池中的最大閑置連接數(shù)。 如果n大于最大開啟連接數(shù),則新的最大閑置連接數(shù)會減小到匹配最大開啟連接數(shù)的限制。 如果n<=0,不會保留閑置連接。

二、CRUD

2.1 建庫建表

我們先在MySQL中創(chuàng)建一個名為sql_test的數(shù)據(jù)庫

CREATE DATABASE sql_test;

進(jìn)入該數(shù)據(jù)庫:

use sql_test;

執(zhí)行以下命令創(chuàng)建一張用于測試的數(shù)據(jù)表:

CREATE TABLE `user` (
    `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(20) DEFAULT '',
    `age` INT(11) DEFAULT '0',
    PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

2.2 查詢

為了方便查詢,我們事先定義好一個結(jié)構(gòu)體來存儲user表的數(shù)據(jù)。

type user struct {
	id   int
	age  int
	name string
}

2.3 單行查詢

單行查詢db.QueryRow()執(zhí)行一次查詢,并期望返回最多一行結(jié)果(即Row)。QueryRow總是返回非nil的值,直到返回值的Scan方法被調(diào)用時,才會返回被延遲的錯誤。

func (db *DB) QueryRow(query string, args ...interface{}) *Row

具體示例代碼:

// 查詢單條數(shù)據(jù)示例
func queryRowDemo() {
	sqlStr := "select id, name, age from user where id=?"
	var u user
	// 確保QueryRow之后調(diào)用Scan方法,否則持有的數(shù)據(jù)庫鏈接不會被釋放
	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\n", u.id, u.name, u.age)
}

2.4 多行查詢

多行查詢db.Query()執(zhí)行一次查詢,返回多行結(jié)果(即Rows),一般用于執(zhí)行select命令。參數(shù)args表示query中的占位參數(shù)。

func (db *DB) Query(query string, args ...interface{}) (*Rows, error)

具體示例代碼:

// 查詢多條數(shù)據(jù)示例
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
	}
	// 關(guān)閉rows釋放持有的數(shù)據(jù)庫鏈接
	defer rows.Close()

	// 循環(huán)讀取結(jié)果集中的數(shù)據(jù)
	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)
	}
}

2.5 插入數(shù)據(jù)

插入、更新和刪除操作都使用Exec方法。

func (db *DB) Exec(query string, args ...interface{}) (Result, error)

Exec執(zhí)行一次命令(包括查詢、刪除、更新、插入等),返回的Result是對已執(zhí)行的SQL命令的總結(jié)。參數(shù)args表示query中的占位參數(shù)。

具體插入數(shù)據(jù)示例代碼如下:

// 插入數(shù)據(jù)
func insertRowDemo() {
	sqlStr := "insert into user(name, age) values (?,?)"
	ret, err := db.Exec(sqlStr, "王五", 38)
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	theID, err := ret.LastInsertId() // 新插入數(shù)據(jù)的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)
}

2.6 更新數(shù)據(jù)

具體更新數(shù)據(jù)示例代碼如下:

// 更新數(shù)據(jù)
func updateRowDemo() {
	sqlStr := "update user set age=? where id = ?"
	ret, err := db.Exec(sqlStr, 39, 3)
	if err != nil {
		fmt.Printf("update failed, err:%v\n", err)
		return
	}
	n, err := ret.RowsAffected() // 操作影響的行數(shù)
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("update success, affected rows:%d\n", n)
}

2.7 刪除數(shù)據(jù)

具體刪除數(shù)據(jù)的示例代碼如下:

// 刪除數(shù)據(jù)
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() // 操作影響的行數(shù)
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("delete success, affected rows:%d\n", n)
}

三、事務(wù)

3.1 什么是事務(wù)

事務(wù):一個最小的不可再分的工作單元;通常一個事務(wù)對應(yīng)一個完整的業(yè)務(wù)(例如銀行賬戶轉(zhuǎn)賬業(yè)務(wù),該業(yè)務(wù)就是一個最小的工作單元),同時這個完整的業(yè)務(wù)需要執(zhí)行多次的DML(insert、update、delete)語句共同聯(lián)合完成。A轉(zhuǎn)賬給B,這里面就需要執(zhí)行兩次update操作。

在MySQL中只有使用了Innodb數(shù)據(jù)庫引擎的數(shù)據(jù)庫或表才支持事務(wù)。事務(wù)處理可以用來維護(hù)數(shù)據(jù)庫的完整性,保證成批的SQL語句要么全部執(zhí)行,要么全部不執(zhí)行。

3.2 事務(wù)的ACID

通常事務(wù)必須滿足4個條件(ACID):原子性(Atomicity,或稱不可分割性)、一致性(Consistency)、隔離性(Isolation,又稱獨(dú)立性)、持久性(Durability)。

條件解釋
原子性一個事務(wù)(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結(jié)束在中間某個環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯誤,會被回滾(Rollback)到事務(wù)開始前的狀態(tài),就像這個事務(wù)從來沒有執(zhí)行過一樣。
一致性在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預(yù)設(shè)規(guī)則,這包含資料的精確度、串聯(lián)性以及后續(xù)數(shù)據(jù)庫可以自發(fā)性地完成預(yù)定的工作。
隔離性數(shù)據(jù)庫允許多個并發(fā)事務(wù)同時對其數(shù)據(jù)進(jìn)行讀寫和修改的能力,隔離性可以防止多個事務(wù)并發(fā)執(zhí)行時由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。事務(wù)隔離分為不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重復(fù)讀(repeatable read)和串行化(Serializable)。
持久性事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失。

3.3 事務(wù)相關(guān)方法

Go語言中使用以下三個方法實(shí)現(xiàn)MySQL中的事務(wù)操作。 開始事務(wù)

func (db *DB) Begin() (*Tx, error)

提交事務(wù)

func (tx *Tx) Commit() error

回滾事務(wù)

func (tx *Tx) Rollback() error

3.4 事務(wù)示例

下面的代碼演示了一個簡單的事務(wù)操作,該事物操作能夠確保兩次更新操作要么同時成功要么同時失敗,不會存在中間狀態(tài)。

// 事務(wù)操作示例
func transactionDemo() {
	tx, err := db.Begin() // 開啟事務(wù)
	if err != nil {
		if tx != nil {
			tx.Rollback() // 回滾
		}
		fmt.Printf("begin trans failed, err:%v\n", err)
		return
	}
	sqlStr1 := "Update user set age=30 where id=?"
	ret1, err := tx.Exec(sqlStr1, 2)
	if err != nil {
		tx.Rollback() // 回滾
		fmt.Printf("exec sql1 failed, err:%v\n", err)
		return
	}
	affRow1, err := ret1.RowsAffected()
	if err != nil {
		tx.Rollback() // 回滾
		fmt.Printf("exec ret1.RowsAffected() failed, err:%v\n", err)
		return
	}

	sqlStr2 := "Update user set age=40 where id=?"
	ret2, err := tx.Exec(sqlStr2, 3)
	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 ret1.RowsAffected() failed, err:%v\n", err)
		return
	}

	fmt.Println(affRow1, affRow2)
	if affRow1 == 1 && affRow2 == 1 {
		fmt.Println("事務(wù)提交啦...")
		tx.Commit() // 提交事務(wù)
	} else {
		tx.Rollback()
		fmt.Println("事務(wù)回滾啦...")
	}

	fmt.Println("exec trans success!")
}

到此這篇關(guān)于Go語言操作MySQL的知識總結(jié)的文章就介紹到這了,更多相關(guān)Go語言操作MySQL內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go 1.21新增的slices包中切片函數(shù)用法詳解

    Go 1.21新增的slices包中切片函數(shù)用法詳解

    Go 1.21新增的 slices 包提供了很多和切片相關(guān)的函數(shù),可以用于任何類型的切片,本文通過代碼示例為大家介紹了部分切片函數(shù)的具體用法,感興趣的小伙伴可以了解一下
    2023-08-08
  • 為什么不建議在go項(xiàng)目中使用init()

    為什么不建議在go項(xiàng)目中使用init()

    這篇文章主要介紹了為什么不建議在go項(xiàng)目中使用init(),本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • Go語言中關(guān)閉帶緩沖區(qū)的頻道實(shí)例分析

    Go語言中關(guān)閉帶緩沖區(qū)的頻道實(shí)例分析

    這篇文章主要介紹了Go語言中關(guān)閉帶緩沖區(qū)的頻道,實(shí)例分析了帶緩沖區(qū)頻道的原理與用法,以及關(guān)閉帶緩沖區(qū)頻道的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • golang包循環(huán)引用的幾種解決方案總結(jié)

    golang包循環(huán)引用的幾種解決方案總結(jié)

    golang有包循環(huán)引用問題,用過的應(yīng)該都知道,下面這篇文章主要給大家介紹了關(guān)于golang包循環(huán)引用的幾種解決方案,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • logrus hook輸出日志到本地磁盤的操作

    logrus hook輸出日志到本地磁盤的操作

    這篇文章主要介紹了logrus hook輸出日志到本地磁盤的操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 詳解Golang五種原子性操作的用法

    詳解Golang五種原子性操作的用法

    本文主要介紹了詳解Golang五種原子性操作的用法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 一文詳解Go語言切片是如何擴(kuò)容的

    一文詳解Go語言切片是如何擴(kuò)容的

    切片是一個擁有相同類型元素的可變長度的序列,它是基于數(shù)組類型做的一層封裝。它非常靈活,支持自動擴(kuò)容。所以本文就來看看Go語言切片是如何擴(kuò)容的吧
    2023-04-04
  • 淺談Go語言中的次方用法

    淺談Go語言中的次方用法

    這篇文章主要介紹了淺談Go語言中的次方用法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go外部依賴包從vendor,$GOPATH和$GOPATH/pkg/mod查找順序

    Go外部依賴包從vendor,$GOPATH和$GOPATH/pkg/mod查找順序

    這篇文章主要介紹了Go外部依賴包vendor,$GOPATH和$GOPATH/pkg/mod下查找順序,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • go語言檢測文件是否存在的方法

    go語言檢測文件是否存在的方法

    這篇文章主要介紹了go語言檢測文件是否存在的方法,實(shí)例分析了Go語言文件操作的相關(guān)技巧,需要的朋友可以參考下
    2015-03-03

最新評論