Merge pull request #4542 from flycash/rollback
Support RollbackUnlessCommit
This commit is contained in:
commit
10ea897525
@ -6,6 +6,7 @@
|
|||||||
- Add sonar check and ignore test. [4432](https://github.com/beego/beego/pull/4432) [4433](https://github.com/beego/beego/pull/4433)
|
- Add sonar check and ignore test. [4432](https://github.com/beego/beego/pull/4432) [4433](https://github.com/beego/beego/pull/4433)
|
||||||
- Update changlog.yml to check every PR to develop branch.[4427](https://github.com/beego/beego/pull/4427)
|
- Update changlog.yml to check every PR to develop branch.[4427](https://github.com/beego/beego/pull/4427)
|
||||||
- Fix 4396: Add context.param module into adapter. [4398](https://github.com/beego/beego/pull/4398)
|
- Fix 4396: Add context.param module into adapter. [4398](https://github.com/beego/beego/pull/4398)
|
||||||
|
- Support `RollbackUnlessCommit` API. [4542](https://github.com/beego/beego/pull/4542)
|
||||||
- Remove `duration` from prometheus labels. [4391](https://github.com/beego/beego/pull/4391)
|
- Remove `duration` from prometheus labels. [4391](https://github.com/beego/beego/pull/4391)
|
||||||
- Fix `unknown escape sequence` in generated code. [4385](https://github.com/beego/beego/pull/4385)
|
- Fix `unknown escape sequence` in generated code. [4385](https://github.com/beego/beego/pull/4385)
|
||||||
- Using fixed name `commentRouter.go` as generated file name. [4385](https://github.com/beego/beego/pull/4385)
|
- Using fixed name `commentRouter.go` as generated file name. [4385](https://github.com/beego/beego/pull/4385)
|
||||||
|
|||||||
@ -232,6 +232,14 @@ func (t *TxDB) Rollback() error {
|
|||||||
return t.tx.Rollback()
|
return t.tx.Rollback()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TxDB) RollbackUnlessCommit() error {
|
||||||
|
err := t.tx.Rollback()
|
||||||
|
if err != sql.ErrTxDone {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var _ dbQuerier = new(TxDB)
|
var _ dbQuerier = new(TxDB)
|
||||||
var _ txEnder = new(TxDB)
|
var _ txEnder = new(TxDB)
|
||||||
|
|
||||||
|
|||||||
@ -503,6 +503,22 @@ func (f *filterOrmDecorator) Rollback() error {
|
|||||||
return f.convertError(res[0])
|
return f.convertError(res[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *filterOrmDecorator) RollbackUnlessCommit() error {
|
||||||
|
inv := &Invocation{
|
||||||
|
Method: "RollbackUnlessCommit",
|
||||||
|
Args: []interface{}{},
|
||||||
|
InsideTx: f.insideTx,
|
||||||
|
TxStartTime: f.txStartTime,
|
||||||
|
TxName: f.txName,
|
||||||
|
f: func(c context.Context) []interface{} {
|
||||||
|
err := f.TxCommitter.RollbackUnlessCommit()
|
||||||
|
return []interface{}{err}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
res := f.root(context.Background(), inv)
|
||||||
|
return f.convertError(res[0])
|
||||||
|
}
|
||||||
|
|
||||||
func (f *filterOrmDecorator) convertError(v interface{}) error {
|
func (f *filterOrmDecorator) convertError(v interface{}) error {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -402,6 +402,10 @@ func (f *filterMockOrm) Rollback() error {
|
|||||||
return errors.New("rollback")
|
return errors.New("rollback")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *filterMockOrm) RollbackUnlessCommit() error {
|
||||||
|
return errors.New("rollback unless commit")
|
||||||
|
}
|
||||||
|
|
||||||
func (f *filterMockOrm) DBStats() *sql.DBStats {
|
func (f *filterMockOrm) DBStats() *sql.DBStats {
|
||||||
return &sql.DBStats{
|
return &sql.DBStats{
|
||||||
MaxOpenConnections: -1,
|
MaxOpenConnections: -1,
|
||||||
|
|||||||
@ -160,3 +160,8 @@ func MockCommit(err error) *Mock {
|
|||||||
func MockRollback(err error) *Mock {
|
func MockRollback(err error) *Mock {
|
||||||
return NewMock(NewSimpleCondition("", "Rollback"), []interface{}{err}, nil)
|
return NewMock(NewSimpleCondition("", "Rollback"), []interface{}{err}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MockRollbackUnlessCommit support RollbackUnlessCommit
|
||||||
|
func MockRollbackUnlessCommit(err error) *Mock {
|
||||||
|
return NewMock(NewSimpleCondition("", "RollbackUnlessCommit"), []interface{}{err}, nil)
|
||||||
|
}
|
||||||
@ -241,6 +241,19 @@ func TestTransactionRollback(t *testing.T) {
|
|||||||
assert.Equal(t, mock, err)
|
assert.Equal(t, mock, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTransactionRollbackUnlessCommit(t *testing.T) {
|
||||||
|
s := StartMock()
|
||||||
|
defer s.Clear()
|
||||||
|
mock := errors.New(mockErrorMsg)
|
||||||
|
s.Mock(MockRollbackUnlessCommit(mock))
|
||||||
|
|
||||||
|
//u := &User{}
|
||||||
|
o := orm.NewOrm()
|
||||||
|
txOrm, _ := o.Begin()
|
||||||
|
err := txOrm.RollbackUnlessCommit()
|
||||||
|
assert.Equal(t, mock, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestTransactionCommit(t *testing.T) {
|
func TestTransactionCommit(t *testing.T) {
|
||||||
s := StartMock()
|
s := StartMock()
|
||||||
defer s.Clear()
|
defer s.Clear()
|
||||||
|
|||||||
@ -593,6 +593,10 @@ func (t *txOrm) Rollback() error {
|
|||||||
return t.db.(txEnder).Rollback()
|
return t.db.(txEnder).Rollback()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *txOrm) RollbackUnlessCommit() error {
|
||||||
|
return t.db.(txEnder).RollbackUnlessCommit()
|
||||||
|
}
|
||||||
|
|
||||||
// NewOrm create new orm
|
// NewOrm create new orm
|
||||||
func NewOrm() Ormer {
|
func NewOrm() Ormer {
|
||||||
BootStrap() // execute only once
|
BootStrap() // execute only once
|
||||||
|
|||||||
@ -206,6 +206,13 @@ func (d *dbQueryLog) Rollback() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dbQueryLog) RollbackUnlessCommit() error {
|
||||||
|
a := time.Now()
|
||||||
|
err := d.db.(txEnder).RollbackUnlessCommit()
|
||||||
|
debugLogQueies(d.alias, "tx.RollbackUnlessCommit", "ROLLBACK UNLESS COMMIT", a, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (d *dbQueryLog) SetDB(db dbQuerier) {
|
func (d *dbQueryLog) SetDB(db dbQuerier) {
|
||||||
d.db = db
|
d.db = db
|
||||||
}
|
}
|
||||||
|
|||||||
@ -159,6 +159,7 @@ func throwFail(t *testing.T, err error, args ...interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deprecated using assert.XXX
|
||||||
func throwFailNow(t *testing.T, err error, args ...interface{}) {
|
func throwFailNow(t *testing.T, err error, args ...interface{}) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
con := fmt.Sprintf("\t\nError: %s\n%s\n", err.Error(), getCaller(2))
|
con := fmt.Sprintf("\t\nError: %s\n%s\n", err.Error(), getCaller(2))
|
||||||
@ -2248,27 +2249,64 @@ func TestTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = to.Rollback()
|
err = to.Rollback()
|
||||||
throwFail(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
num, err = o.QueryTable("tag").Filter("name__in", names).Count()
|
num, err = o.QueryTable("tag").Filter("name__in", names).Count()
|
||||||
throwFail(t, err)
|
assert.Nil(t, err)
|
||||||
throwFail(t, AssertIs(num, 0))
|
assert.Equal(t, int64(0), num)
|
||||||
|
|
||||||
to, err = o.Begin()
|
to, err = o.Begin()
|
||||||
throwFail(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
tag.Name = "commit"
|
tag.Name = "commit"
|
||||||
id, err = to.Insert(&tag)
|
id, err = to.Insert(&tag)
|
||||||
throwFail(t, err)
|
assert.Nil(t, err)
|
||||||
throwFail(t, AssertIs(id > 0, true))
|
assert.True(t, id > 0)
|
||||||
|
|
||||||
to.Commit()
|
err = to.Commit()
|
||||||
throwFail(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
num, err = o.QueryTable("tag").Filter("name", "commit").Delete()
|
num, err = o.QueryTable("tag").Filter("name", "commit").Delete()
|
||||||
throwFail(t, err)
|
assert.Nil(t, err)
|
||||||
throwFail(t, AssertIs(num, 1))
|
assert.Equal(t, int64(1), num)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTxOrmRollbackUnlessCommit(t *testing.T) {
|
||||||
|
o := NewOrm()
|
||||||
|
var tag Tag
|
||||||
|
|
||||||
|
// test not commited and call RollbackUnlessCommit
|
||||||
|
to, err := o.Begin()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
tag.Name = "rollback unless commit"
|
||||||
|
rows, err := to.Insert(&tag)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.True(t, rows > 0)
|
||||||
|
err = to.RollbackUnlessCommit()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
num, err := o.QueryTable("tag").Filter("name", tag.Name).Delete()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, int64(0), num)
|
||||||
|
|
||||||
|
// test commit and call RollbackUnlessCommit
|
||||||
|
|
||||||
|
to, err = o.Begin()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
tag.Name = "rollback unless commit"
|
||||||
|
rows, err = to.Insert(&tag)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.True(t, rows > 0)
|
||||||
|
|
||||||
|
err = to.Commit()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
err = to.RollbackUnlessCommit()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
num, err = o.QueryTable("tag").Filter("name", tag.Name).Delete()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
assert.Equal(t, int64(1), num)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransactionIsolationLevel(t *testing.T) {
|
func TestTransactionIsolationLevel(t *testing.T) {
|
||||||
|
|||||||
@ -110,10 +110,35 @@ type TxBeginner interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TxCommitter interface {
|
type TxCommitter interface {
|
||||||
|
txEnder
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction beginner
|
||||||
|
type txer interface {
|
||||||
|
Begin() (*sql.Tx, error)
|
||||||
|
BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction ending
|
||||||
|
type txEnder interface {
|
||||||
Commit() error
|
Commit() error
|
||||||
Rollback() error
|
Rollback() error
|
||||||
|
|
||||||
|
// RollbackUnlessCommit if the transaction has been committed, do nothing, or transaction will be rollback
|
||||||
|
// For example:
|
||||||
|
// ```go
|
||||||
|
// txOrm := orm.Begin()
|
||||||
|
// defer txOrm.RollbackUnlessCommit()
|
||||||
|
// err := txOrm.Insert() // do something
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// txOrm.Commit()
|
||||||
|
// ```
|
||||||
|
RollbackUnlessCommit() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Data Manipulation Language
|
// Data Manipulation Language
|
||||||
type DML interface {
|
type DML interface {
|
||||||
// insert model data to database
|
// insert model data to database
|
||||||
@ -592,18 +617,6 @@ type dbQuerier interface {
|
|||||||
// QueryRow(query string, args ...interface{}) *sql.Row
|
// QueryRow(query string, args ...interface{}) *sql.Row
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// transaction beginner
|
|
||||||
type txer interface {
|
|
||||||
Begin() (*sql.Tx, error)
|
|
||||||
BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// transaction ending
|
|
||||||
type txEnder interface {
|
|
||||||
Commit() error
|
|
||||||
Rollback() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// base database struct
|
// base database struct
|
||||||
type dbBaser interface {
|
type dbBaser interface {
|
||||||
Read(context.Context, dbQuerier, *modelInfo, reflect.Value, *time.Location, []string, bool) error
|
Read(context.Context, dbQuerier, *modelInfo, reflect.Value, *time.Location, []string, bool) error
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user