go 使用mysql
阅读原文时间:2023年07月08日阅读:2

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()
}