golang:Mysql数据库操作(连接、CRUD、SQL预处理、事务)

连接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!
}

如果连接失败,可以进行以下尝试:

  1. 首先打开电脑的命令行模式,输入mysql看看是否有信息,如果没有,可能是未启动mysqld服务、没有配置环境变量等原因。
  2. 使用命令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
    }
}

事务

事务操作主要用以下三个方法:

  1. 开启事务:func (db *DB) Begin() (*Tx, error)
  2. 提交事务:func (tx *Tx) Commit() error
  3. 回滚事务: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()
}

猜你喜欢

转载自blog.csdn.net/lena7/article/details/120256450