93人参与 • 2025-04-24 • Golang
事务是数据库操作中的一个逻辑单元,由一系列的数据库操作组成。这一系列操作要么全部执行并且提交,要么全部回滚,确保数据的一致性和完整性。事务具有以下四个主要特性,通常被称为acid特性:
在go语言中,使用database/sql包进行事务的基本步骤如下:
db.begin()方法启动一个事务,返回一个事务对象tx。tx执行多个sql操作,如tx.exec()、tx.query()等。tx.commit()提交事务;如果出现错误,使用tx.rollback()回滚事务。事务的使用场景
注意事项
数据库连接方法
dsn := "username:password@tcp(127.0.0.1:3306)/dbname"
| 方法名 | 描述 | 示例 |
|---|---|---|
sql.open() | 打开数据库连接 | db, err := sql.open("mysql", dsn) |
db.ping() | 测试数据库连接是否有效 | err = db.ping() |
db.close() | 关闭数据库连接 | defer db.close() |
事务方法
| 方法名 | 描述 | 示例 |
|---|---|---|
db.begin() | 开始一个事务 | tx, err := db.begin() |
tx.rollback() | 回滚事务 | tx.rollback() |
tx.commit() | 提交事务 | err = tx.commit() |
查询和执行方法
| 方法名 | 描述 | 示例 |
|---|---|---|
tx.exec() | 执行不返回结果的sql语句,用于create、insert、update、delete等操作 | tx.exec("create table ...") |
tx.query() | 执行返回多行结果的sql查询 | rows, err := tx.query("select ...") |
tx.queryrow() | 执行返回单行结果的sql查询 | tx.queryrow("select ...") |
stmt.exec() | 使用预处理语句执行sql语句 | stmt.exec("f", "g") |
预处理语句
| 方法名 | 描述 | 示例 |
|---|---|---|
tx.prepare() | 创建预处理语句 | stmt, err := tx.prepare(...) |
stmt.close() | 关闭预处理语句 | defer stmt.close() |
查询结果处理
| 方法名 | 描述 | 示例 |
|---|---|---|
rows.next() | 逐行迭代查询结果 | rows.next() |
rows.scan() | 将当前行的列值赋值给变量 | rows.scan(&s1, &s2) |
rows.err() | 检查查询和迭代过程中的错误 | rows.err() |
rows.close() | 关闭结果集,释放相关资源 | defer rows.close() |
预处理语句是指在数据库中提前编译和优化的sql语句模板,可以在之后多次重复使用。预处理语句的主要优点如下:
在go语言中,使用预处理语句的基本步骤如下:
tx.prepare()方法创建一个预处理语句对象stmt。stmt.exec()方法执行预处理语句,传递参数。stmt.close()方法释放相关资源。以下是一个使用预处理语句的示例:
stmt, err := tx.prepare("insert into table1 (column1, column2) values(?, ?)")
if err != nil {
fmt.printf("准备预处理语句失败:%v\n", err)
return
}
defer stmt.close()
// 第一次执行
_, err = stmt.exec("f", "g")
if err != nil {
tx.rollback()
fmt.printf("执行预处理语句第一次失败:%v\n", err)
return
}
// 第二次执行
_, err = stmt.exec("h", "i")
if err != nil {
tx.rollback()
fmt.printf("执行预处理语句第二次失败:%v\n", err)
return
} 在这个示例中,预处理语句一次创建,多次执行,提升了效率,并降低了sql注入的风险。
注意事项
总的示例代码:
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
const (
dsn = "username:password@tcp(localhost:3306)/test"
)
func main() {
db, err := sql.open("mysql", dsn)
if err != nil {
fmt.printf("打开数据库连接失败:%v\n", err)
return
}
defer db.close()
if err := db.ping(); err != nil {
fmt.printf("数据库连接不可用:%v\n", err)
return
}
transactionexample(db)
}
func transactionexample(db *sql.db) {
tx, err := db.begin()
if err != nil {
fmt.printf("开始事务失败:%v\n", err)
return
}
defer func() {
if err != nil {
fmt.println("事务回滚中...")
rollbackerr := tx.rollback()
if rollbackerr != nil && rollbackerr != sql.errtxdone {
fmt.printf("事务回滚失败:%v\n", rollbackerr)
}
}
}()
// 创建表
fmt.println("创建表...")
err = createtable(tx)
if err != nil {
return
}
// 插入数据
fmt.println("插入数据到table1...")
err = insertdata(tx)
if err != nil {
return
}
// 更新数据
fmt.println("更新table1的值...")
err = updatedata(tx)
if err != nil {
return
}
// 删除数据
fmt.println("删除数据...")
err = deletedata(tx)
if err != nil {
return
}
// 查询多行数据
fmt.println("查询多行数据...")
err = querymultirows(tx)
if err != nil {
return
}
// 查询单行数据
fmt.println("查询单行数据...")
err = querysinglerow(tx)
if err != nil {
return
}
// 预处理语句插入数据
fmt.println("使用预处理语句插入数据...")
err = insertwithprepare(tx)
if err != nil {
return
}
// 提交事务
fmt.println("提交事务...")
err = tx.commit()
if err != nil {
fmt.printf("提交事务失败:%v\n", err)
return
}
fmt.println("事务处理成功。")
}
func createtable(tx *sql.tx) error {
_, err := tx.exec("create table if not exists table1 (column1 nchar(10), column2 nchar(10))")
return err
}
func insertdata(tx *sql.tx) error {
_, err := tx.exec("insert into table1 (column1, column2) values ('a','b'), ('c','d'), ('e','f')")
return err
}
func updatedata(tx *sql.tx) error {
_, err := tx.exec("update table1 set column1 = 'c' where column1 = 'a'")
return err
}
func deletedata(tx *sql.tx) error {
_, err := tx.exec("delete from table1 where column1 = 'b'")
return err
}
func querymultirows(tx *sql.tx) error {
rows, err := tx.query("select * from table1")
if err != nil {
return err
}
defer rows.close()
for rows.next() {
var s1, s2 string
err := rows.scan(&s1, &s2)
if err != nil {
return fmt.errorf("扫描失败:%v", err)
}
fmt.printf("table1数据:%s, %s\n", s1, s2)
}
if err := rows.err(); err != nil {
return fmt.errorf("遍历table1失败:%v", err)
}
return nil
}
func querysinglerow(tx *sql.tx) error {
var c string
err := tx.queryrow("select column1 from table1 where column1 = 'e'").scan(&c)
if err != nil {
if err == sql.errnorows {
fmt.println("没有找到匹配的行。")
} else {
return fmt.errorf("查询单行数据失败:%v", err)
}
return nil
}
fmt.printf("单行数据:%s\n", c)
return nil
}
func insertwithprepare(tx *sql.tx) error {
stmt, err := tx.prepare("insert into table1 (column1, column2) values(?, ?)")
if err != nil {
return fmt.errorf("准备预处理语句失败:%v", err)
}
defer stmt.close()
_, err = stmt.exec("f", "g")
if err != nil {
return fmt.errorf("执行预处理语句失败:%v", err)
}
return nil
} 到此这篇关于golang的database.sql包和事务处理操作步骤的文章就介绍到这了,更多相关golang的database.sql包内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论