package main /* 下划線(如:import _ hello/imp)的作用:當導入一個包時,該包下的文件里所有init()函數都會被執行, 然而,有些時候我們並不需要把整個包都導入進來,僅僅是是希望它執行init()函數而已。 這個時候就可以使用 import _ 引用該包。 即使用【import _ 包路徑】只是引用該包,僅僅是為了調用init()函數,所以無法通過包名來調用包中的其他函數。 */ import ( "fmt" _ "github.com/go-sql-driver/mysql" "database/sql" ) /* 一、database/sql接口介紹 可發者根據定義的接口來開發響應數據庫驅動 1 sql.Register 注冊數據庫驅動,第三方開發數據庫驅動時都會實現init函數,在init里面調動Register(name string, driver.Driver) 例如: sqlite3驅動 func init(){ sql.Register("sqlite3",&AQLiteDriver{}) } mysql驅動 var d = Driver{proto:"tcp",raddr:"1270.0.1:3306"} func init(){ Register("SET NAMES utf8") sql.Register("mymysql",&d) } 2 driver.Driver Driver是一個數據庫驅動的接口,定義了一個metod:Open(name string) type Driver interface { Open(name string) (Conn,err) { } } 這個方法返回一個數據庫的Conn接口,返回的Conn只能用來進行一次goroutine的操作 go gorountineA(Conn) go gorountineB(Conn) 這樣兩個goroutine 里面使用這個Conn,可能會導致程序不知道某個操作究竟是由哪個goroutine發起大,結果可能是將A操作結果返回了B ,B的操作結果給了A 3 diver.Conn 數據庫連接的接口 這個Conn只能應用在一個goroutine,不能用在多個goroutine,詳情參考2 type Conn interface{ Prepare(query string) (Stmt,err) Close() error Begin() (Tx,error) } Prepare函數返回與當前連接的相關的執行sql語句的准備狀態,可以進行查詢、刪除等操作 Close函數 關閉當前連接,執行釋放連接擁有的資源等清理工作 Begin函數 返回一個代表事務處理的Tx,通過他可以進行查詢、更新等操作,或者對事物進行回滾、遞交 4 driver.Stmt 是一種准備好的狀態,和Conn相關聯 只能應用於一個goroutine type Stmt interface { Close() error Numlnput()int Exec(args []Value) (Result,error) Query(args []Value) (Rows,error) } Close函數 關閉當前連接,如果當前正在執行query,query還是有效並返回rows數據 Numlnput函數 返回當前預留參數的個數,當返回 大於等於零時數據庫驅動就會智能檢查調用者的參數。當數據庫驅動包不知道預留參數的時候,返回-1 Exec函數 執行Prepare准備好的sql,傳入參數執行update/insert等操作,返回Result數據 Query函數 執行Prepare准備好的sql,傳入需要的參數執行select操作,返回Rows結果集 5 dirver.Execer type Execer interface { Exec(query string, args []Value) (Result,error) } 這是一個Conn可選擇實現的接口 如果沒有定義這個接口,在調用DB.Exec時,就會實現調用Prepare返回Stmt,然后執行Stmt的Exec,最后關閉Stmt 6 dirver.Result type Result interface { LastInsertId()(int64,error) RowsAffected()(int64,error) } 這是執行Update/Insert等操作返回的結果接口定義 LastInsertId函數 返回有數據庫執行插入操作得到的自增ID號 RowsAffected函數 返回query操作影響的數據條目數 7 driver.Rows type Rows interface { Columns() []string Close() error Next(dest []Value) error } 這是執行查詢返回的結果集接口 Columns函數 返回查詢數據庫表的字段信息,這個返回的slice和sql查詢字段一一對應,而不是返回整個表的所有字段 Close函數 用來關閉Rows迭代器 Next函數 用來返回下一條數據,把數據賦值給dest。dest里面的元素必須是dirver,Value的值除了string,返回的數據中心所有的string都必須轉換成[]byte。如果最后沒有數據了,Next函數最后返回io.EOF 8 driver.RowsAffected 其實就是基礎類型是int64的自定義類型 type RowsAffected int64 9 dirver.Value type Value interface{} 這是一個空接口,可以容納任何數據 Value要么是nil,要么是下面的任意一種 int64 float64 bool []byte string time.Time 10 driver.ValueConverter type ValueConverter interface { // ConvertValue converts a value to a driver Value. 把普通的值轉化成dirver.Value的接口 ConvertValue(v interface{}) (Value, error) } 12 dirver.Valuer type Valuer interface{ Value() (Value,error) } valuer接口定義了一個返回dirver.Value的方式 */ /* 二使用mysql數據庫 go語言中支持mysql的驅動,有些支持database/sql標准,有些是采用了自己的實現接口。比較常用的: https://github.com/Go-SQL-Driver/MYSQL 支持database/sql 【比較新,支持長連接,線程安全,完全支持database/sql接口】 https://github.com/ziutek/mymysql 支持database/sql 也支持自定義的接口 https://github.com/Philio/GoMySQL 不支持database/sql,自定義接口 */ /* 准備 CREATE TABLE test.userinfo ( uid INT auto_increment NOT null primary key, username varchar(100) NULL, departname varchar(100) NULL, created DATE NULL ) CREATE TABLE test.userdetail ( uid INT auto_increment NOT null primary key, intro TEXT NULL, profile TEXT NULL ) */ func checkERR(err error){ if err!=nil{ panic(err) } } func main() { //打開數據庫驅動 /* 補充 數據庫信息支持: user@unix(/path/to/socket)/dbname?charset=utf8 user:password@tcp(ip:port)/dbname?charset=utf8 user:password@/dbname user:password@tcp([de:ad:be:ef:ca:fe]:80)/dbname */ db,err:=sql.Open("mysql","root:qwer123!@tcp(10.10.187.150:3306)/test") checkERR(err) //增 //返回准備要執行的sql操作,然后返回准備完畢的執行狀態 =? 可以一定程度上防止sql注入 //stmt,err:=db.Prepare("insert userinfo set username=?,departname=?,created=?") //checkERR(err) //// 執行 stmt准備好的sql語句 //res,err:=stmt.Exec("wzg","研發","2022-02-10") //checkERR(err) //id,err:=res.LastInsertId() //checkERR(err) //fmt.Println(id) ////改 //stmt,err :=db.Prepare("update userinfo set username=? where uid=?") //checkERR(err) //res,err := stmt.Exec("wzgupdate",2) //checkERR(err) //affect,err:= res.RowsAffected() //checkERR(err) //fmt.Println(affect) ////查 ////執行sql返回rows結果集 //rows,err:=db.Query("select * from userinfo") //checkERR(err) ////Next()方法可以到下一個結果 //for rows.Next(){ // var uid int // var username string // var department string // var created string // err = rows.Scan(&uid,&username,&department,&created) //Scan copies the columns in the current row into the values pointed at by dest. The number of values in dest must be the same as the number of columns in Rows. // checkERR(err) // fmt.Println(uid) // fmt.Println(username) // fmt.Println(department) // fmt.Println(created) //} //刪 stmt,err := db.Prepare("delete from userinfo where uid=?") checkERR(err) res,err:= stmt.Exec(2) checkERR(err) affect,err:= res.RowsAffected() checkERR(err) fmt.Println(affect) db.Close() }
