Go Web --- 使用MySQL
简略介绍
在Go语言中,如果要连接并操作数据库,那么就要自己安装对应的数据库驱动,每一种数据库的驱动都不同,但是Go语言提供了一套抽象层接口来调用底层的驱动,类似于PHP语言中PDO。
安装mysql驱动
使用go语言的go get命令即可,
go get github.com/go-sql-driver/mysql
可能你在运行这条命令的时候出现这种情况:
warning: GOPATH set to GOROOT (/usr/local/go) has no effect
这个时候,你可以查看一下你的PATH环境变量和GOROOT环境变量。看是不是你的GOROOT也在PATH里面。
首先,如果你的go安装目录是在/usr/local目录下,那么你就可以不要设置GOROOT环境变量,只有当你的安装目录不是/usr/local目录下的时候,才指定GOROOT环境变量,
我的go安装路径是/usr/local/go目录,所以我的PATH变量值为/usr/local/go/bin。
各种包,包括这里的mysql驱动,都默认安装在$HOME/go/src/github.com目录下的。
设置连接数据库的参数
func Open(driverName, dataSourceName string) (*DB, error)
package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" //_表示只使用init方法 ) func main() { //func Open(driverName, dataSourceName string) (*DB, error) _, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8") if err != nil { panic(err) } else { fmt.Println("数据库连接成功") } }
注意,这个代码上面的标题并不是“连接数据库”,而是设置“连接数据库的参数”,因为:
这里有一个坑:上面这段代码,无论你的用户名,还是密码,甚至是ip和端口都错了,那么他也会输出“数据库连接成功”。
Go Web编程(Go web Programming)中这样说的:
Open函数在执行的时候并不会真正的与数据库进行连接,他甚至不会检查用户给定的参数;Open函数的真正作用是设置好连接数据库所需的各个结构,并以惰性的方式,等到真正需要时才建立相应的数据库连接。
怎么样才知道你的数据库参数是否正确呢?执行一条SQL语句就行了。
执行SQL语句的两个方法
func (s *Stmt) Query(args ...interface{}) (*Rows, error)
用来执行select这种有结果集的SQL查询操作
func (s *Stmt) Exec(args ...interface{}) (Result, error)
用来执行update、insert、delete这几种数据库操作命令
测试使用的数据表(shop)
mysql> desc fruit; +-------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | char(30) | NO | | NULL | | | price | int(11) | NO | | 99 | | +-------+----------+------+-----+---------+----------------+
使用Query方法进行select操作,返回结果集
//func Open(driverName, dataSourceName string) (*DB, error) db, _ := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8") //关闭数据库连接 //func (db *DB) Close() error defer db.Close() //func (db *DB) Query(query string, args ...interface{}) (*Rows, error) rows, _ := db.Query("select * from fruit") //获取结果集中的字段名 //func (rs *Rows) Columns() ([]string, error) fields, _ := rows.Columns() fmt.Println(fields) //[id name age gender] //声明几个变量,用来保存从数据库中读出的每一行记录 var id int var name string var price int //循环遍历结果集 //func (rs *Rows) Next() bool for rows.Next() { //将结果集中的一行记录的值赋值给变量 //func (rs *Rows) Scan(dest ...interface{}) error rows.Scan(&id, &name, &price) //注意:必须和结果集的字段数量相同,并且顺序、字段名必须对应,否则保存到变量中的数据会有问题 fmt.Println(id, name, price) } //释放结果集,注意,结果集是在数据取完之后释放,不是取一条数据就释放一次 rows.Close()
使用QueryRow获取一条记录
func (db *DB) QueryRow(query string, args ...interface{}) *Row
QueryRow使用起来很方便:QueryRow("sql").Scan("field1","field2")
使用Exec方法进行增删改
insert
db, _ := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8") defer db.Close() //func (db *DB) Exec(query string, args ...interface{}) (Result, error) result, _ := db.Exec("insert into fruit (id,name,price) values (5,'pomelo',8)") //func (dr driverResult) LastInsertId() (int64, error) id, _ := result.LastInsertId() fmt.Println(id) //5 //func (dr driverResult) RowsAffected() (int64, error) num, _ := result.RowsAffected() fmt.Println(num) //1
update
db, _ := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8") defer db.Close() result, _ := db.Exec("update fruit set price=20 where id > 3") //func (dr driverResult) RowsAffected() (int64, error) num, _ := result.RowsAffected() fmt.Println(num) //2
delete
db, _ := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8") defer db.Close() result, _ := db.Exec("delete from fruit") //func (dr driverResult) RowsAffected() (int64, error) num, _ := result.RowsAffected() fmt.Println(num) // 5
预处理SQL
使用预处理就是将SQL语句和参数分离,参数可以单独绑定值,这样一定程度上可以防止SQL注入。
进行与处理之后,返回的Stmt对象,Stmt对象也有Exec和Query方法,并且这两个方法和DB.Exec、DB.Query、DB.QueryRow方法完全相同。
预处理查
db, _ := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8") defer db.Close() //func (db *DB) Prepare(query string) (*Stmt, error) stmt, _ := db.Prepare("select * from fruit where id=? or name=?") //如果预处理的SQL语句是查操作,那么就使用Query方法执行SQL命令,返回结果集 //func (s *Stmt) Query(args ...interface{}) (*Rows, error) rows, _ := stmt.Query(3, "apple") var id int var name string var price int for rows.Next() { rows.Scan(&id, &name, &price) fmt.Println(id, name, price) } rows.Close()
预处理增删改
db, _ := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8") defer db.Close() stmt, _ := db.Prepare("update fruit set price=30 where id>?") //func (s *Stmt) Exec(args ...interface{}) (Result, error) result, _ := stmt.Exec(1) fmt.Println(result.RowsAffected()) //4 <nil> stmt, _ = db.Prepare("insert into fruit values (?,?,?)") result, _ = stmt.Exec(6, "kaki", 20) // 6 <nil> fmt.Println(result.LastInsertId()) stmt, _ = db.Prepare("delete from fruit where id > ?") result, _ = stmt.Exec(3) fmt.Println(result.RowsAffected()) //3 <nil>