Golang中的Mysql操作


go语言中 database/sql包提供了保证SQL或类SQL数据库的泛用接口,常用的数据库驱动有 github.com/go-sql-driver/mysql

初始化连接

以下代码定义了一个全局变量 db,它将用于保存数据库连接的实例。然后定义了initDB 函数负责初始化数据库连接。它使用给定的连接字符串创建一个数据库连接实例,然后通过 Ping 方法检查是否能够成功连接到数据库。在这里,CheckError 函数用于检查和处理每个步骤可能发生的错误。

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB

func CheckError(err error, arg string) {
	if err != nil {
		fmt.Printf("%s err:%v", arg, err)
	}
}

func initDB() (err error) {
	dsn := "root:123456@tcp(127.0.0.1:3306)/users"
	db, err = sql.Open("mysql", dsn)
	CheckError(err, "Open")
	err = db.Ping()
	CheckError(err, "ping")
	return nil
}

func main() {
	err := initDB()
	CheckError(err, "init db")
	defer db.Close()
}

查询数据

先定义一个struct来存储查询的数据

type userData struct {
	id       int
	age      int
	name     string
}

单行查询

在 Go 语言中,db.QueryRow() 用于执行一次查询并期望返回最多一行结果。如果没有找到结果,它不会返回 nil,而是返回一个实现了 Row 接口的非空值。

在调用 QueryRow() 后,通常会使用 Scan() 方法从结果中提取数据。Scan() 方法负责将结果的列映射到相应的变量,并在需要时触发底层查询的执行。在调用 Scan() 之前,QueryRow() 不会执行实际的查询。

// 单行查询db.QueryRow()执行一次查询,并期望返回最多一行结果(即Row)
func queryRowDemo() {
	sqlStr := "select id,name,age from user where id=?"
	var u userData
	// 非常重要:确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放
	err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.name, &u.age)
	CheckError(err, "scan")
	fmt.Printf("id:%d,name:%s,username:%s", u.id, u.name, u.age)
}

多行查询

多行查询db.Query()执行一次查询,返回多行结果(即Rows),一般用于执行select命令。

func queryMultiRowDemo() {
	sqlStr := "select id,name,age from user where id>?"
	rows, err := db.Query(sqlStr, 0)
	CheckError(err, "query")
	defer rows.Close()

	// 循环读取结果集中的数据
	for rows.Next() {
		var u userData
		err := rows.Scan(&u.id, &u.name, &u.age)
		CheckError(err, "rows scan")
		fmt.Printf("id:%d,name:%s,age:%d\n", u.id, u.name, u.age)
	}
}

以上代码使用 rows.Next() 遍历结果集中的每一行,然后使用 rows.Scan 将当前行的数据扫描到相应的变量中。

插入数据

插入、更新和删除操作都使用Exec方法。

func InsertRowDemo() {
	sqlStr := "insert into user(name,age) values (?,?)"
	ret, err := db.Exec(sqlStr, "王五", 18)
	CheckError(err, "insert")
	theID, err := ret.LastInsertId()
	CheckError(err, "LastInsertId")
	fmt.Println("insert success,the id is", theID)
}

使用 ret.LastInsertId() 获取最后插入的 ID,通常在表中有一个自增的主键时使用。

更新数据

这里将 user 表中 id 为 5 的行的 age 列更新为 100。并使用 ret.RowsAffected() 获取受影响的行数,即更新操作实际影响的行数。

func UpdateRowDemo() {
	sqlStr := "update user set age=? where id=?"
	ret, err := db.Exec(sqlStr, 100, 5)
	CheckError(err, "update")
	n, err := ret.RowsAffected() // 操作影响的行数
	CheckError(err, "RowsAffected")
	fmt.Printf("update success, affected rows:%d\n", n)
}

删除数据

func DeleteRowDemo() {
	sqlStr := "delete from user where id=?"
	ret, err := db.Exec(sqlStr, 5)
	CheckError(err, "delete")
	n, err := ret.RowsAffected()
	CheckError(err, "RowsAffected")
	fmt.Printf("delete success,affected rows:%d\n", n)
}

预编译

预编译执行过程:

  1. 把SQL语句分成两部分,命令部分与数据部分。
  2. 先把命令部分发送给MySQL服务端,MySQL服务端进行SQL预处理。
  3. 然后把数据部分发送给MySQL服务端,MySQL服务端对SQL语句进行占位符替换。
  4. MySQL服务端执行完整的SQL语句并将结果返回给客户端。

Golang中通过database/sql使用下面的Prepare方法来实现预处理操作。

func (db *DB) Prepare(query string) (*Stmt, error)

查询数据

func PrepareQueryDemo() {
	Sqlstr := "select id,name,age from user where id > ?"
	stmt, err := db.Prepare(Sqlstr)
	CheckError(err, "Prepare stmt")
	defer stmt.Close()
	rows, err := stmt.Query(0)
	CheckError(err, "Query")
	defer rows.Close()
	for rows.Next() {
		var u userData
		err := rows.Scan(&u.id, &u.name, &u.age)
		CheckError(err, "rows scan")
		fmt.Printf("id:%d,name:%s,age:%d\n", u.id, u.name, u.age)
	}
}

插入数据

func InsertQueryDemo() {
	Sqlstr := "insert into user(name,age) values(?,?)"
	stmt, err := db.Prepare(Sqlstr)
	CheckError(err, "stmt")
	defer stmt.Close()
	_, err = stmt.Exec("wangdong", 20)
	CheckError(err, "insert")
	fmt.Println("insert success")
}

更新和删除操作类似插入操作。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lum1n0us

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值