Closed smiletrl closed 8 months ago
What happened: XA 一个事务里跑多个sql不能正常执行 What you expected to happen: XA 一个事务里跑多个sql可以正常执行
How to reproduce it (as minimally and precisely as possible): 使用xa basic sample里代码, 重复执行 db.ExecContext两次, 报错
db.ExecContext
func insertData(ctx context.Context) error { fmt.Printf("insert start \n\n\n") sql := "INSERT INTO `order_tbl` ( `user_id`, `commodity_code`, `count`, `money`, `descs`) VALUES (?, ?, ?, ?, ?);" ret, err := db.ExecContext(ctx, sql, "NO-100001", "C100000", 100, nil, "init desc") if err != nil { fmt.Printf("insert failed, err:%v\n", err) return err } rows, err := ret.RowsAffected() if err != nil { fmt.Printf("insert failed, err:%v\n", err) return err } fmt.Printf("insert success 1: %d.\n\n\n", rows) sql = "INSERT INTO `order_tbl` ( `user_id`, `commodity_code`, `count`, `money`, `descs`) VALUES (?, ?, ?, ?, ?);" ret, err = db.ExecContext(ctx, sql, "NO-100001", "C100000", 100, nil, "init desc") if err != nil { fmt.Printf("insert failed, err:%v\n", err) return err } rows, err = ret.RowsAffected() if err != nil { fmt.Printf("insert failed, err:%v\n", err) return err } fmt.Printf("insert success 2: %d.\n\n\n", rows) return nil } func sampleInsert(ctx context.Context) { tm.WithGlobalTx(ctx, &tm.GtxConfig{ Name: "XASampleLocalGlobalTx_Insert", Timeout: time.Second * 30, }, insertData) }
报错, panic
should NEVER happen: setAutoCommit from true to false while xa branch is active
Anything else we need to know?:
// BeginTx like common transaction. but it just exec XA START func (c *XAConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { if !tm.IsGlobalTx(ctx) { tx, err := c.Conn.BeginTx(ctx, opts) return tx, err } c.autoCommit = false c.txCtx = types.NewTxCtx() c.txCtx.DBType = c.res.dbType c.txCtx.TxOpt = opts c.txCtx.ResourceID = c.res.resourceID c.txCtx.XID = tm.GetXID(ctx) c.txCtx.TransactionMode = types.XAMode tx, err := c.Conn.BeginTx(ctx, opts) if err != nil { return nil, err } c.tx = tx if !c.autoCommit { if c.xaActive { return nil, errors.New("should NEVER happen: setAutoCommit from true to false while xa branch is active") } baseTx, ok := tx.(*Tx) if !ok { return nil, fmt.Errorf("start xa %s transaction failure for the tx is a wrong type", c.txCtx.XID) } c.branchRegisterTime = time.Now() if err := baseTx.register(c.txCtx); err != nil { c.cleanXABranchContext() return nil, fmt.Errorf("failed to register xa branch %s, err:%w", c.txCtx.XID, err) } c.xaBranchXid = XaIdBuild(c.txCtx.XID, c.txCtx.BranchID) c.keepIfNecessary() if err = c.start(ctx); err != nil { c.cleanXABranchContext() return nil, fmt.Errorf("failed to start xa branch xid:%s err:%w", c.txCtx.XID, err) } c.xaActive = true } return &XATx{tx: tx.(*Tx)}, nil }
这里的逻辑好像定死了一个XAConn 不能区分两次不同的sql tx. c.autoCommit = false 默认为false,c.xaActive = true 执行一次,这个(c *XAConn) BeginTx 就无法再次执行。
c.autoCommit = false
c.xaActive = true
(c *XAConn) BeginTx
这个问题可以通过将 db.ExecContext(ctx, sql, "NO-100001", "C100000", 100, nil, "init desc")这里的sql改为多条sql 语句即可。
db.ExecContext(ctx, sql, "NO-100001", "C100000", 100, nil, "init desc")
What happened: XA 一个事务里跑多个sql不能正常执行 What you expected to happen: XA 一个事务里跑多个sql可以正常执行
How to reproduce it (as minimally and precisely as possible): 使用xa basic sample里代码, 重复执行
db.ExecContext
两次, 报错报错, panic
Anything else we need to know?:
这里的逻辑好像定死了一个XAConn 不能区分两次不同的sql tx.
c.autoCommit = false
默认为false,c.xaActive = true
执行一次,这个(c *XAConn) BeginTx
就无法再次执行。