Closed chen56 closed 5 years ago
The standard way of using this library for that would be to use db.Begin()
however it looks like you're using sqlx, which is probably why you can't.
If I changed goqu
to accept a interface ( since sqlx.DB and Tx both keep the same contract as sql.DB) when creating a goqu.Database would that suit your needs?
I added the change I described in my previous comment. This should allow you to create a new goqu db instance with your sqlx instance. From there you can just do db.From
to get a new transaction instance.
Let me know if this helps!
thanks, You're so quick!
I have some Legacy Code (sqlx and goqu.v5) , mixture use sqlx and goqu.v5 in one tx
like this :
import (
"context"
"database/sql"
"github.com/jmoiron/sqlx"
"github.com/sirupsen/logrus"
"gopkg.in/doug-martin/goqu.v5"
_ "gopkg.in/doug-martin/goqu.v5/adapters/mysql"
)
func XXXXXXQuery(){
mydatebase:=NewDb(sqlx.MustConnect("mysql", "localhost:3306................"))
err = mydatebase.InTxContext(ctx, &sql.TxOptions{ReadOnly: true}, func(myTx *mysqlx.Tx) error {
//use sqlx tx
row := tx.Tx.QueryRowx("select * from abc")
...
// use goqu Tx
found, err := tx.Goqu.From(goqu.I("abc").As("c")).Select("c.xxx").ScanStruct(&res)
...
return err
})
}
// DB ext
type DB struct {
DB *sqlx.DB
Goqu *goqu.Database
}
// Tx ext
type Tx struct {
Tx *sqlx.Tx
Goqu *goqu.TxDatabase
}
// NewDb
func NewDb(db *sqlx.DB) *DB {
return &DB{
DB: db,
Goqu: goqu.New("mysql", db.DB),
}
}
// InTxContext
func (db *DB) InTxContext(ctx context.Context, opts *sql.TxOptions, txFunc func(tx *Tx) error) (err error) {
tx, err := db.DB.BeginTxx(ctx, opts)
if err != nil {
return
}
return inTx(tx, txFunc)
}
//InTx ref: https://stackoverflow.com/questions/16184238/database-sql-tx-detecting-commit-or-rollback
func (db *DB) InTx(txFunc func(tx *Tx) error) (err error) {
tx, err := db.DB.Beginx()
if err != nil {
return
}
return inTx(tx, txFunc)
}
func inTx(sqlxTx *sqlx.Tx, txFunc func(tx *Tx) error) (err error) {
tx := &Tx{sqlxTx, &goqu.TxDatabase{Dialect: sqlxTx.DriverName(), Tx: sqlxTx.Tx}}
defer func() {
if r := recover(); r != nil {
//已在一个panic中,不理会Rollback的err
err := tx.Tx.Rollback()
logrus.Error(err)
// re-throw panic after Rollback
panic(r)
}
if err != nil {
//err已非空,不理会Rollback的err
err := tx.Tx.Rollback()
logrus.Error(err)
return
}
// err==nil, commit; 如果commit失败,则返回err
err = tx.Tx.Commit()
}()
err = txFunc(tx)
return err
}
in goqu.v7 , I saw your new code,Still unable to do this:
goquTx, err := db.Goqu.Begin()
if err != nil {
return
}
myTx:=Tx{
Tx: ?????, // sqlx.Tx: sqlx also does not support NewTx(otherTx)
goqu: goquTx,
}
Ok I added a goqu.NewTx
function which you should be able to pass in the sqlx.Tx into to create a new goqu.TxDatabase
in goqu.v5, i can use
goqu.TxDatabase{...}
create a goqu tx, but v7 how to do this :