简介
Go 语言中的 database/sql包定义了对数据库的一系列操作,database/sql/driver包定义了应被数据库驱动实现的接口,这些接口会被sql包使用.但是 Go语言没有提供任何官方的数据库驱动,所以需要导入第三方的数据库驱动,不过连接数据库之后对数据库操作的大部分代码都使用sql包
1.获取数据库连接
(1).创建一个db.go文件,导入database/sql包以及第三方驱动包
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
(2).定义两个全局变量
var (
Db *sqlDB
err error
)
DB结构体的说明
(3).创建init函数,在函数体中调用sql包的Open函数获取连接
func init() {
Db, err := sql.Open("mysql", "root:root@tcp(localhost:3306)/test")
if err != nil {
panic(err.Error())
}
}
Open函数说明
参数dataSourceName的格式:
数据库用户名:数据库密码@[tcp(localhost:3306)]/数据库名
完整代码:
package utils
import (
"database/sql"
_"github.com/go-sql-driver/mysql"
)
var (
Db *sql.DB
err error
)
func init() {
Db, err = sql.Open("mysql", "root:123456@/go-data")
if err != nil {
panic(err.Error())
}
}
2.增删改查操作
(1).在连接test数据库中创建一个users表
create table users (
id int primary key auto_increment,
username varchar(255) unique not null,
password varchar(255) not null,
email varchar(255)
)
(2).向users表中插入一条数据
1).创建user.go文件,文件中编写以下代码
package model
import(
"fmt"
"go_code/web_app/sql/utils"
)
需要用到的database/sql包接口
代码示例如下:
package model
import (
"fmt"
"go_code/web_app/sql/utils"
)
//User 结构体
type User struct {
ID int
Name string
Password string
Email string
}
//AddUser 添加User的方法一:带预编译的添加
func (user *User) AddUser() error {
//sql语句
sql := "insert into user(`name`, `password`, `email`) values(?, ?, ?)"
//预编译
inStmt, err := utils.Db.Prepare(sql)
if err != nil {
fmt.Println("预编译出错", err)
return err
}
//执行
result, err2 := inStmt.Exec("admin", "123456", "admin@qq.com")
if err2 != nil {
fmt.Println("执行出错", err2)
return err2
}
Id, err3 := result.LastInsertId()
if err3 != nil {
fmt.Println("插入后返回的自增id错误", err3)
return err3
}
fmt.Println("插入成功, 返回的id=", Id)
return nil
}
//AddUser 添加User的方法二:不带预编译,直接执行的添加
func (user *User) AddUser2() error {
//sql语句
sql := "insert into user(name, password, email) values(?, ?, ?)"
//执行
result, err := utils.Db.Exec(sql, "admin2", "123456", "admin2@qq.com")
if err != nil {
fmt.Println("执行出错", err)
return err
}
Id, err2 := result.LastInsertId()
if err2 != nil {
fmt.Println("插入后返回的自增id错误", err2)
return err2
}
fmt.Println("插入成功, 返回的id=", Id)
return nil
}
3.单元测试
(1).简介
顾名思义,单元测试(unit test ) ,就是一种为验证单元的正确性而设置的自动化测试,一个单元就是程序中的一个模块化部分、一般来说,一个单元通常会与程序中的一个函数或者一个方法相对应,但这并不是必须的.Go的单元测试需要用到 testing 包以及go test 命令,而且对测试文件也有以下要求:
1).被测试的源文件和测试文件必须位于同一个包下
2).测试文件必须要以_test.go结尾
*虽然Go对测试文件_test.go的前缀没有强制要求,不过一般都设置为被测试的文件的文件名,如:要对user.go进行测试,那么测试文件的名字通常设置为user_test.go
3).测试文件中的测试函数为TestXxx(t *testing.T)
*其中 Xxx 的首字母必须是大写的英文宇母
*函数参数必须是 test.T的指针类型(如果是 Benchmark 测试则参数是testing.B的指针类型)
测试代码如下:
package model
import (
"fmt"
"testing"
)
//执行测试: go test, 查看测试的详细信息: go test -v
//TestMain()函数可以在测试函数执行之前做一些其他操作
func TestMain(m *testing.M) {
fmt.Println("测试开始")
//通过m.Run()来执行测试函数
m.Run()
}
func TestUser(t *testing.T) {
fmt.Println("开始测试User中的方法")
//通过t.Run()来执行子测试函数
t.Run("测试添加用户", testAddUser)
}
//如果函数名不是Test,那么该函数默认不执行,可以将它设置成一个子测试函数来执行
//func TestAddUser(t *testing.T) {
func testAddUser(t *testing.T) {
fmt.Println("添加测试用户")
user := &User{}
//调用添加用户方法
user.AddUser()
user.AddUser2()
}
user.go:
package model
import (
"fmt"
"go_code/web_app/sql/utils"
)
//User 结构体
type User struct {
ID int
Name string
Password string
Email string
}
//AddUser 添加User的方法一:带预编译的添加
func (user *User) AddUser() error {
//sql语句
sql := "insert into user(`name`, `password`, `email`) values(?, ?, ?)"
//预编译
inStmt, err := utils.Db.Prepare(sql)
if err != nil {
fmt.Println("预编译出错", err)
return err
}
//执行
result, err2 := inStmt.Exec("admin", "123456", "admin@qq.com")
if err2 != nil {
fmt.Println("执行出错", err2)
return err2
}
Id, err3 := result.LastInsertId()
if err3 != nil {
fmt.Println("插入后返回的自增id错误", err3)
return err3
}
fmt.Println("插入成功, 返回的id=", Id)
return nil
}
//AddUser 添加User的方法二:不带预编译,直接执行的添加
func (user *User) AddUser2() error {
//sql语句
sql := "insert into user(name, password, email) values(?, ?, ?)"
//执行
result, err := utils.Db.Exec(sql, "admin2", "123456", "admin2@qq.com")
if err != nil {
fmt.Println("执行出错", err)
return err
}
Id, err2 := result.LastInsertId()
if err2 != nil {
fmt.Println("插入后返回的自增id错误", err2)
return err2
}
fmt.Println("插入成功, 返回的id=", Id)
return nil
}
//GetUserById 根据用户id从数据中查询一条记录
func (user *User) GetUserById() (*User, error) {
//sql语句
sql := "select id, name, password, email from user where id = ?"
//执行
row := utils.Db.QueryRow(sql, user.ID)
//声明
var id int
var name string
var password string
var email string
err := row.Scan(&id, &name, &password, &email)
if err != nil {
return nil, err
}
u := &User{
ID: id,
Name: name,
Password: password,
Email: email,
}
return u, nil
}
//GetUsers 获取数据库中所有数据
func (user *User) GetUsers() ([]*User, error) {
//sql语句
sql := "select id, name, password, email from user"
//执行
rows, err := utils.Db.Query(sql)
if err != nil {
return nil, err
}
//定义一个User切片
var users []*User
//循环rows
for rows.Next() {
//声明
var id int
var name string
var password string
var email string
err := rows.Scan(&id, &name, &password, &email)
if err != nil {
return nil, err
}
u := &User{
ID: id,
Name: name,
Password: password,
Email: email,
}
users = append(users, u)
}
return users, nil
}
user_test.go:
package model
import (
"fmt"
"testing"
)
//执行测试: go test, 查看测试的详细信息: go test -v
//TestMain()函数可以在测试函数执行之前做一些其他操作
func TestMain(m *testing.M) {
fmt.Println("测试开始")
//通过m.Run()来执行测试函数
m.Run()
}
func TestUser(t *testing.T) {
fmt.Println("开始测试User中的方法")
//通过t.Run()来执行子测试函数
//t.Run("测试添加用户", testAddUser)
//t.Run("测试获取用户", testGetUserById)
t.Run("测试获取所有用户", testGetUsers)
}
//如果函数名不是Test,那么该函数默认不执行,可以将它设置成一个子测试函数来执行
//func TestAddUser(t *testing.T) {
func testAddUser(t *testing.T) {
fmt.Println("添加测试用户")
user := &User{}
//调用添加用户方法
err := user.AddUser()
if err != nil {
fmt.Println(err)
}
err2 := user.AddUser2()
if err2 != nil {
fmt.Println(err2)
}
}
//测试获取用户信息
func testGetUserById(t *testing.T) {
fmt.Println("测试查询一条记录")
user := &User{
ID: 1,
}
//调用获取User的方法
u, _ := user.GetUserById()
fmt.Println("得到User的信息:", u)
}
//测试获取所有用户信息
func testGetUsers(t *testing.T) {
fmt.Println("测试查询所有记录")
user := &User{}
//调用获取所有User的方法
us, _ := user.GetUsers()
//遍历切片
for k, u := range us {
fmt.Printf("第%d个用户信息:%v\n", k + 1, u)
}
}