Go标准库中没有数据库驱动,如果实现数据库连接与操作,参见获取第三方的数据库驱动。本文以MySQL为例,我们使用go-sql-driver实现数据库的连接和操作,首先在CMD窗口下安装驱动go-sql-driver,指令如下。
go get github.com/go-sql-driver/mysql
数据库驱动安装成功后,在GoLand(ide)中使用go-sql-driver实现数据库的连接和操作,实现方式首先连接MySQL的某个数据库,生成数据库对象db,然后使用数据库对象db对数据表实现怎删改查操作。
go-sql-driver提供2种数据查询方式:Query和QueryRow。Query是查询多行数据,也可以查询单行数据,适用范围较广;QueryRow只能查询单行数据,该对象能调用的方法较少,局限性较大。不管Query或QueryRow,两者只查询数据表的数据,如果想将数据表的字段与数据一一对应,需要我们编写函数方法实现,废话不多说,直接看代码。
package main
import (
"database/sql"
"encoding/json"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func GetAll(rows *sql.Rows) []map[string]string {
// 判断传入的查询结果是否为nil
if rows == nil {
return nil
}
// 定义返回值的数据类型(定义为数组,元素类型为映射,映射的数据为字符串类型)
var result []map[string]string
// 获取查询结果rows的列名(即字段名)
cols, _ := rows.Columns()
// 定义数组byte
rawResult := make([][]byte, len(cols))
// 定义数组dest
dest := make([]interface{}, len(cols))
// 将byte数组的内存地址对应分配给dest
for i, _ := range rawResult {
dest[i] = &rawResult[i]
}
// 遍历每行数据
for rows.Next() {
// 将每行的数据分别存入数组dest
// 由于数组dest和数组byte的内存地址是相同的
// 因此两个数组的数据也是相同,只不过两个数组的每个元素的数据格式不同
rows.Scan(dest...)
// 根据列的个数定义相应的映射对象sresult
sresult := make(map[string]string, len(cols))
// 将当前数据写入映射对象sresult
for i, raw := range rawResult {
if raw == nil {
sresult[cols[i]] = ""
} else {
sresult[cols[i]] = string(raw)
}
}
// 将数据写入数组result
result = append(result, sresult)
}
// 将数组result作为返回值
return result
}
func main(){
// 连接MySQL数据库
db, _ := sql.Open("mysql", "root:1234@tcp(127.0.0.1:3306)/music_db?charset=utf8")
// 查询方式一,先使用Prepare再使用Query或QueryRow
p , _ := db.Prepare("select * from index_song")
rows, _ := p.Query()
// 查询方式二,直接使用Query或QueryRow
//rows, _ := db.Query("select * from index_song")
s2 := GetAll(rows)
for _, v := range s2{
// 将映射对象转化JSON数据
mjson, _ :=json.Marshal(v)
mString :=string(mjson)
fmt.Println(mString)
}
// 查询方式三,查询单条数据
// 适合单条数据的某些字段,如果查询全部字段,建议使用Query
row := db.QueryRow("select name,album from index_song where id=1")
var name,album string
row.Scan(&name,&album)
fmt.Println(name,album)
}
上述代码中,涉及了两个Go的基础语法,下划线(_)和三个点(…),本文不再详细讲述语法知识,读者可以点击相关链接查看。
函数方法GetAll是将Query查询对象rows作为函数参数,函数返回值result为数组类型,数组元素的数据类型为映射对象。函数首先从查询对象rows获取数据表的字段名,生成对象cols,将对象cols的字段名作为返回值result的映射对象的key,而数据表的数据作为映射对象的value。具体的实现过程不过多讲述,详细可看代码注释。
数据的增改删操作主要由Exec方法实现,实现方法较为简单,直接看到代码即可理解
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main(){
// 连接MySQL数据库
db, _ := sql.Open("mysql", "root:1234@tcp(127.0.0.1:3306)/music_db?charset=utf8")
// 新增数据
ret, _ := db.Exec("insert into index_label(id,name) values(15,'测试测试')")
// LastInsertId是获取数据新增后的ID
insID, _ := ret.LastInsertId()
fmt.Println(insID)
// 修改数据
ret2, _ := db.Exec("update index_label set name= 'GOGO' where id = ?", 15)
// RowsAffected是获取已被修改的数据总数
aff_nums, _ := ret2.RowsAffected()
fmt.Println(aff_nums)
// 删除数据
ret3, _ := db.Exec("delete from index_label where id = ?",15)
delNums, _ := ret3.RowsAffected()
fmt.Println(delNums)
}
事务由Begin函数方法实现,只需在数据库连接对象调用Begin函数方法即可,然后由Begin函数方法生成的对象执行数据操作即可,可以根据执行结果判断当前事务是否执行或回滚,详细代码如下。
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
func main(){
// 连接MySQL数据库
db, _ := sql.Open("mysql", "root:1234@tcp(127.0.0.1:3306)/music_db?charset=utf8")
//开启事务
tx, _ := db.Begin()
//id为1的price+1,id为2的price-1
ret4, _ := tx.Exec("update index_label set name = '测试事务1' where id = ?", 10)
ret5, _ := tx.Exec("update index_label set name = '测试事务2' where id = ?", 2)
//如果id不存在,受影响行数则为0
//接收影响行数,为0则失败
updNums1, _ := ret4.RowsAffected()
updNums2, _ := ret5.RowsAffected()
if updNums1 > 0 && updNums2 > 0 { //只有两条更新同时成功,那么才提交
tx.Commit() //提交事务
fmt.Println("Success")
} else { //否则回滚
tx.Rollback() //回退事务
fmt.Println("Fail")
}
}
综合上述,本博文讲述了如何使用go-sql-driver实现数据库MySQL数据库操作,下一节将讲述如何使用ORM框架实现数据库操作。