连接mysql数据库
1、创建数据库表
create table student (
id int NOT NULL AUTO_INCREMENT,
name varchar(20),
age int
)
2、添加数据
insert into student values(1001,"lena",21),(1002,"titiy",22);
3、go get mysql
如果是第一次连接mysql数据库,需要先拉取mysql所需要的包
go get -u github.com/go-sql-driver/mysql
该过程我遇到了一个代理失败的error,如相同可参考:https://blog.csdn.net/lena7/article/details/120254809
4、Golang测试连接数据库
由于在实际中并未使用到mysql的包,但在sql.Open
中传入mysql会自动查找mysql
,并不是直接使用到,我使用的工具Goland会自动将未直接使用导包删除掉,因此我们可以在mysql的导包前面加_
。
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql" // 必须导入否则无法识别mysql
)
func ConnMysql() {
// 格式:账号:密码@tcp(数据库ip:数据库端口)/数据库名称
url := "root:root@tcp(127.0.0.1:3306)/test"
// func Open(数据库驱动名称,连接信息) (*DB, error)
db, err := sql.Open("mysql", url)
if err != nil {
fmt.Println("conn err :",err)
return
}
defer db.Close()
// 尝试链接
err = db.Ping()
if err != nil {
fmt.Println("ping err :",err)
return
}
fmt.Println("conn success!") // conn success!
}
如果连接失败,可以进行以下尝试:
- 首先打开电脑的命令行模式,输入
mysql
看看是否有信息,如果没有,可能是未启动mysqld服务、没有配置环境变量等原因。 - 使用命令
mysql -u 账号 -p
回车后输入密码,查看是否能够进入数据库。如果在命令行能够进入,连接应该没什么问题。
数据库操作
CRUD
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt"
)
var db *sql.DB
func Conn() {
url := "root:root@tcp(127.0.0.1:3306)/test"
db, _ = sql.Open("mysql", url)
// 尝试链接
err := db.Ping()
if err != nil {
fmt.Println("ping err :",err)
return
}
fmt.Println("conn success!") // conn success!
}
/**
创建student结构体用于操作数据库表student
create table student (
id int primary key,
name varchar(20),
age int
*/
type Student struct {
id int
name string
age int
}
// 查询一条记录:QueryRow
func QueryOne(id int) Student {
sql := "select * from student where id = ?"
s:=Student{
}
// 查询后需要用Scan将查询结果写入结构体中
err := db.QueryRow(sql,id).Scan(&s.id, &s.name, &s.age)
if err != nil {
fmt.Println("select err :",err)
}
return s
}
// 查询多条记录
func QueryAgeMore(age int) []Student {
sql := "select * from student where age > ?"
rows, err := db.Query(sql, age)
if err != nil {
fmt.Println("select err :",err)
return nil
}
defer rows.Close()
var students []Student
// 当有下一行时返回true
for rows.Next() {
var s Student
err := rows.Scan(&s.id, &s.name, &s.age)
if err != nil {
fmt.Println("scan err :",err)
break
}
students=append(students, s)
}
return students
}
// 写操作(增删改)都使用Exec方法
// 新增数据:返回自增的id
func Insert(s Student) int {
sql := "insert into student(name,age) values(?,?)"
res, err := db.Exec(sql,s.name, s.age)
if err != nil {
fmt.Println("insert err :",err)
return 0
}
id, err := res.LastInsertId() // 返回的id属性列必须是自动递增的
if err != nil {
fmt.Println("get last id err :",err)
return s.id
}
return int(id)
}
// 更新数据:返回影响行数
func UpdateOne(s Student) int64 {
sql := "update student set age = ? where id = ?"
res, err := db.Exec(sql, s.age, s.id)
if err != nil {
fmt.Println("update err :", err)
return 0
}
i, err := res.RowsAffected()
if err != nil {
fmt.Println("get effected row num err :", err)
return 0
}
return i
}
// 删除数据
func DeleteOne(id int) int {
sql := "delete from student where id = ?"
res, err := db.Exec(sql, id)
if err != nil {
fmt.Println("delete err :",err)
return 0
}
i, err := res.RowsAffected()
if err != nil {
fmt.Println("get effected row num err :",err)
return 0
}
return int(i)
}
测试代码
import (
"fmt"
"reflect"
"testing"
)
func TestQueryOne(t *testing.T) {
Conn()
s := QueryOne(1001)
var expert=Student{
1001,"lena",21}
if !reflect.DeepEqual(s,expert) {
t.Errorf("result is %v,not expert %v",s,expert)
}
}
func TestQueryAgeMore(t *testing.T) {
Conn()
// 查询十岁以上的学生
s := QueryAgeMore(10)
fmt.Println(s) // [{1001 lena 21} {1002 kity 20}]
}
func TestInsert(t *testing.T) {
Conn()
s:=Student{
0,"tity",15}
res := Insert(s)
if !reflect.DeepEqual(res,1005) {
t.Errorf("res = %v",res)
}
}
func TestUpdateOne(t *testing.T) {
s := Student{
1004, "peity", 6}
i := UpdateOne(s)
var e int64
e=1
if !reflect.DeepEqual(i, e) {
t.Errorf("reflected row : %v", i)
}
}
func TestDeleteOne(t *testing.T) {
Conn()
i := DeleteOne(1005)
if !reflect.DeepEqual(i,1) {
t.Errorf("reflected row : %v",i)
}
}
SQL语句预处理
实现sql语句预处理主要依赖一个函数:func (db *DB) Prepare(query string) (*Stmt, error)
具体使用代码如下:
/**
* @Author: lena
* @Date: 2021/10/17 19:11
* @Description: sql预处理
* @Version: 1.0.0
*/
package mysql
import (
"database/sql"
"fmt"
)
// 初始化数据库链接
func init() {
url := "root:root@tcp(127.0.0.1:3306)/test"
// db存在于"db/mysql/crud.go"文件中
db, _ = sql.Open("mysql", url)
// 尝试链接
err := db.Ping()
if err != nil {
fmt.Println("ping err :", err)
return
}
fmt.Println("conn success!") // conn success!
}
// 预处理方法:func (db *DB) Prepare(query string) (*Stmt, error)
// 查询单条记录sql语句预处理
func QueryOnePretreatment() {
sqlStr := "select * from student where id = ?"
stmt, err := db.Prepare(sqlStr)
if err != nil {
fmt.Println("prepare err:", err)
return
}
defer stmt.Close()
var s Student
// 查询单行:func (s *Stmt) QueryRow(args ...interface{}) *Row {
err = stmt.QueryRow(1001).Scan(&s.id, &s.name, &s.age)
if err != nil {
fmt.Println("query row err :",err)
return
}
fmt.Println(s)
// 查询不同条件,但同一个sql
err = stmt.QueryRow(1002).Scan(&s.id, &s.name, &s.age)
if err != nil {
fmt.Println("query row err :",err)
return
}
fmt.Println(s)
}
// 查询多条记录sql语句预处理
func QueryPretreatment() {
sql:="select * from student where age > ?"
stmt, err := db.Prepare(sql)
if err != nil {
fmt.Println("prepare err :",err)
return
}
defer stmt.Close()
// 查询所有满足条件的记录:func (s *Stmt) Query(args ...interface{}) (*Rows, error)
rows, err := stmt.Query(10)
if err != nil {
fmt.Println("query err :",err)
return
}
defer rows.Close()
// 当有下一行的时候,指向下一行。若没有下一行则退出循环
for rows.Next() {
var s Student
err = rows.Scan(&s.id, &s.name, &s.age)
if err != nil {
fmt.Println("rows scan err :",err)
return
}
fmt.Println(s)
}
}
// 更新sql语句预处理
func UpdataPretreatment() {
sql:="update student set age = ? where id = ?"
stmt, err := db.Prepare(sql)
if err != nil {
fmt.Println("prepare err :",err)
return
}
defer stmt.Close()
// 更新:func (s *Stmt) Exec(args ...interface{}) (Result, error)
_, err = stmt.Exec(12, 1002)
if err != nil {
fmt.Println("update err :",err)
return
}
// 第二次更新
_, err = stmt.Exec(12, 1003)
if err != nil {
fmt.Println("update err :",err)
return
}
}
事务
事务操作主要用以下三个方法:
- 开启事务:func (db *DB) Begin() (*Tx, error)
- 提交事务:func (tx *Tx) Commit() error
- 回滚事务:func (tx *Tx) Rollback() error
代码如下:
func Affair() {
// 开启事务:func (db *DB) Begin() (*Tx, error)
tx, err := db.Begin()
if err != nil {
// 事务已经开启
if tx != nil {
// 事务回滚
tx.Rollback()
}
fmt.Println("tx start err :",err)
return
}
sql := "update student set age = ? where id = ?"
// 执行sql:func (tx *Tx) Exec(query string, args ...interface{}) (Result, error)
exec, err := tx.Exec(sql, 2, 1002)
if err != nil {
fmt.Println("tx exec err :",err)
tx.Rollback()
return
}
// 返回受影响行数
affected, err := exec.RowsAffected()
if err != nil {
fmt.Println("rows affected err :",err)
tx.Rollback()
return
}
fmt.Println("affected rows :",affected)
// 再执行一条语句 省略是否成功的判断操作
tx.Exec(sql, 3, 1003)
// 提交事务:func (tx *Tx) Commit() error
tx.Commit()
}