Database Interface

Overview

The sub-transaction barrier in dtm needs to interact with the database. The xa transaction mode also needs to interact with the database. The interaction interface currently defined by dtm is compatible with the standard sql library. Therefore, when developing using dtm, you can directly pass sql.DB/sql.Tx.

Most of the projects in practice use more advanced orm libraries, such as gorm and ent, etc. For such usage, interface adaptation is required.

In order to keep the dependencies of dtm as small as possible, the example of dtm is given only for gorm. For other orms, the usage will be explained in the documentation.

GORM

Examples in examples/http_saga_gorm_barrier|http_gorm_xa

barrier example.

  barrier := MustBarrierFromGin(c)
  // Manually open the transaction
  tx := dbGet().DB.Begin()
	return dtmcli.ResultSuccess, barrier.Call(tx.Statement.ConnPool.(*sql.Tx), func(db dtmcli.DB) error {
		return tx.Exec("update dtm_busi.user_account set balance = balance + ? where user_id = ?" , -req.Amount, 2).Error
	})

xa Example.

  return XaClient.XaLocalTransaction(c.Request.URL.Query(), func(db *sql.DB, xa *dtmcli.Xa) (interface{}, error) {
    // gorm provides an interface to construct gorm.DB from the standard sql.
    gdb, err := gorm.Open(mysql.New(mysql.Config{
      Conn: db,
    }), &gorm.Config{})
    if err ! = nil {
      return nil, err
    }
    dbr := gdb.Exec("update dtm_busi.user_account set balance=balance-? where user_id=?" , reqFrom(c).Amount, 1)
    return dtmcli.ResultSuccess, dbr.Error
  })

GOQU

barrier example.

	dialect := goqu.Dialect("mysql")
	sdb, err := dbGet().DB.DB()
	if err ! = nil {
		return nil, err
	}
	tx, err := dialect.DB(sdb).Begin()
	return dtmcli.ResultSuccess, barrier.Call(tx, func(db dtmcli.DB) error {
		_, err := tx.Exec("update dtm_busi.user_account set balance = balance + ? where user_id = ?" , -req.Amount, 2)
		return err
	})

xa example

  return XaClient.XaLocalTransaction(c.Request.URL.Query(), func(db *sql.DB, xa *dtmcli.Xa) (interface{}, error) {
    dialect := goqu.Dialect("mysql")
    godb := dialect.DB(db)
    _, err := godb.Exec("update dtm_busi.user_account set balance=balance-? where user_id=?" , reqFrom(c).Amount, 1)
    return dtmcli.ResultSuccess, err
  })

XORM

Please note that the pr was just raised to xorm on 2021-08-21, exposing sql.Tx, which has been merged but not yet released version, so you need to install the latest version

go get -u xorm.io/xorm@7cd6a74c9f

barrier example.

	x, _ := xorm.NewEngineWithDB("mysql", "dtm", core.FromDB(sdbGet()))
	se := x.NewSession()
	defer se.Close()
	err := se.
	if err ! = nil {
		return nil, err
	}
	return dtmcli.ResultSuccess, barrier.Call(se.Tx().Tx, func(db dtmcli.DB) error {
		_, err := se.Exec("update dtm_busi.user_account set balance = balance + ? where user_id = ?" , -req.Amount, 2)
		return err
	})

xa example

  return XaClient.XaLocalTransaction(c.Request.URL.Query(), func(db *sql.DB, xa *dtmcli.Xa) (interface{}, error) {
    xdb, _ := xorm.NewEngineWithDB("mysql", "dtm", core.FromDB(db))
    _, err := xdb.Exec("update dtm_busi.user_account set balance=balance-? where user_id=?" , reqFrom(c).Amount, 1)
    return dtmcli.ResultSuccess, err
  })