doufei2662 2016-07-15 12:48
浏览 395

在Go lang的一个事务中使用* sql.DB对象运行多个funcs的惯用方式

Let we have 2 methods

func createClient(db *sql.DB, ...) error // creates a new client
func createOrder(db *sql.DB, ...) error // creates a new order

Each of these method can be run on some *sql.DB, for example,

var mainDb *sql.DB // initialized somewhere in main() method

func orderHandler(r,w) {
   ...
   err := createOrder(mainDb, ...)
   ...
}

But what if i want to run both these methods in one transaction. For example,

func importOrdersHandler(r,w) {
     ...
     tx, err:= mainDb.Begin()
     ...
     err = createClient(tx, clientData) // but method defined on *sql.DB, not *sql.Tx ?!
     err = createOrder(tx, orderData)
     ...

My solution:

Define a wrapper around *sql.DB, *sql.Tx:

type Database struct {
   db *sql.DB
   tx *sql.Tx
}

// Redefine all standart methods from sql package, such as
// Exec(...)
// Query(..)
// QueryRow(...)

// Also method to run commands in one transaction:

func TransactionDo(db *sql.DB, body func(*Database) error) error {
  tx, err :=  db.Begin()
  ...
  d, err := NewDb(nil, tx)
  ....
  err = body(d)
  ...
  return tx.Commit()
}

In this way our ordersImportHandler can be realized like that:

 func importOrdersHandler(r,w) {

   for row := range parseFile(formFile(r)) {
     ...
     err := TransactionDo(mainDb, func(d *Database) error {
        err = createClient(d, clientData)
        ...
        err = createOrder(d, orderData)
    // if an error occurs in TransactionDo then transaction wiil be
    // rollbacked, else commit it

createClient, createOrder must be rewrited to use *Database object insted of *sql.DB

What do you think about such solution? May be there another better and idiomatic way to do that

  • 写回答

2条回答 默认 最新

  • douwei1930 2016-07-15 13:03
    关注

    I used an interface (that the library squirrel also uses)

    type Database interface {
        Exec(query string, args ...interface{}) (sql.Result, error)
        Query(query string, args ...interface{}) (*sql.Rows, error)
        QueryRow(query string, args ...interface{}) *sql.Row
    }
    

    Then you can just pass write the functions

    func createClient(db *Database, ...) error // creates a new client
    func createOrder(db *Database, ...) error // creates a new order
    
    评论

报告相同问题?

悬赏问题

  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等
  • ¥15 matlab 用yalmip搭建模型,cplex求解,线性化处理的方法
  • ¥15 qt6.6.3 基于百度云的语音识别 不会改
  • ¥15 关于#目标检测#的问题:大概就是类似后台自动检测某下架商品的库存,在他监测到该商品上架并且可以购买的瞬间点击立即购买下单
  • ¥15 神经网络怎么把隐含层变量融合到损失函数中?
  • ¥15 lingo18勾选global solver求解使用的算法
  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来