Golang PostgreSql数据库事务处理

Golang PostgreSql数据库事务处理

对于数据库执行多个更新操作时,事务会将多个操作当成单个单元处理,要成功都成功,否则都失败。本文通过实例说明Go Sql事务处理。

1. 环境准备

​ 搭建PostgreSql数据库环境,我们打算在postgre数据库中新建表meta_data(id, source),然后插入记录测试事务。

​ go操作数据库的包为"database/sql",这里数据库使用postgreSql,需要导入github.com/lib/pq;下面是准备数据库连接代码。

import (
   "database/sql"
   "fmt"
   _ "github.com/lib/pq"
   uuid "github.com/satori/go.uuid"
   "log"
   "strings"
)

const (
   host     = "192.168.0.111"
   port     = 5432
   user     = "yourDbUser"
   password = "yourDbPassword"
   dbname   = "postgres"
)

var db *sql.DB

func init() {
   var err error
   connStr := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, user, password, dbname)
   db, err = sql.Open("postgres", connStr)
   if err != nil {
      log.Fatal(err)
   }
   db.SetConnMaxLifetime(500)
   db.SetMaxIdleConns(50)
   db.SetMaxOpenConns(10)
   db.Stats()
}

func CheckError(err error) {
   if err != nil {
      panic(err)
   }
}

go默认实现了数据库连接池,无需引入第三方连接池实现。

2. 事务实现

下面是事务示例实现,我们使用postgreSql,因此变量占位符使用 $ , MySql使用 ?。

func InsertData() {
	data := [] string{"DGraph","Redis"}
	sql := "INSERT INTO meta_data(id, source) VALUES($1, $2)"
	tx,err := db.Begin()
	CheckError(err)
	defer tx.Commit()

	for _, item := range data {
		sid := strings.Replace(uuid.NewV4().String(),"-","",-1)
		_, err = db.Exec(sql, sid, item)

		if err != nil {
			_ = tx.Rollback()
            break
		}
	}
}

函数开始之前首先启动事务,使用defer语句确保最后提交事务。接着执行多个插入语句,如果有错误回滚事务。

这个实现没有问题,只是每次需要写和事务相关的代码,显得多余,最好能封装事务相关代码,用户只关心业务。

3. 事务操作封装

上节手动实现了事务,本节对事务操作进行封装,让代码更有通用性。

这里定义UpdateWithTx()函数,其中封装了事务相关代码,具体执行和数据库相关操作通过其函数参数传入。

func UpdateWithTx(fn func(tx *sql.Tx) error) error {
   var tx,err = db.Begin()
   if err != nil{
      return err
   }

   defer func() {
      switch err {
      case nil:
         err = tx.Commit()
      default:
         tx.Rollback()
      }
   }()

   err = fn(tx)

   return err
}

首先获得事务指针,接着写匿名函数,使用defer关键词确保函数执行完成之前自动管控事务。最后执行实际操作的函数并返回状态。下面我们测试该函数。

func TestUpdateWithTx(t *testing.T) {
   UpdateWithTx(func(tx *sql.Tx) error {
      var err error
      data := [] string{"DGraph1","Redis1","MongoDb","BoltDB"}
      sql := "INSERT INTO meta_data(id, source) VALUES($1, $2)"

      for _, item := range data {
         sid := strings.Replace(uuid.NewV4().String(),"-","",-1)
         if _, err = tx.Exec(sql, sid, item); err != nil{
            break
         }
         // err = errors.New("人为错误")
      }
      return err
   })
}

具体业务和上节代码一样,但我们不在关心事务相关代码,用户可测试有错误时是否回滚事务。

4. 总结

本文通过示例介绍了Go Sql事务实现,并对事务相关操作进行封装,使用户只需关心业务操作。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值