Skip to content

Commit 5940839

Browse files
huacnleejinzhu
authored andcommitted
Add db.Transaction method for create Transaction block. (go-gorm#2767)
* Add `db.Transaction` method for create Transaction block. example: ```go func CreateAnimals(db *gorm.DB) error { db.Transaction(func(tx *gorm.DB) error { if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil { // return any error will rollback return err } if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil { return err } // return nil will commit return nil }) } ``` * Ensure rollback when commit has error.
1 parent 179760d commit 5940839

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

main.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,31 @@ func (s *DB) Debug() *DB {
525525
return s.clone().LogMode(true)
526526
}
527527

528+
// Transaction start a transaction as a block,
529+
// return error will rollback, otherwise to commit.
530+
func (s *DB) Transaction(fc func(tx *DB) error) (err error) {
531+
tx := s.Begin()
532+
defer func() {
533+
if r := recover(); r != nil {
534+
err = fmt.Errorf("%s", r)
535+
tx.Rollback()
536+
return
537+
}
538+
}()
539+
540+
err = fc(tx)
541+
542+
if err == nil {
543+
err = tx.Commit().Error
544+
}
545+
546+
// Makesure rollback when Block error or Commit error
547+
if err != nil {
548+
tx.Rollback()
549+
}
550+
return
551+
}
552+
528553
// Begin begins a transaction
529554
func (s *DB) Begin() *DB {
530555
return s.BeginTx(context.Background(), &sql.TxOptions{})

main_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"database/sql"
1010
"database/sql/driver"
11+
"errors"
1112
"fmt"
1213
"os"
1314
"path/filepath"
@@ -469,6 +470,65 @@ func TestTransaction(t *testing.T) {
469470
}
470471
}
471472

473+
func TestTransactionWithBlock(t *testing.T) {
474+
// rollback
475+
err := DB.Transaction(func(tx *gorm.DB) error {
476+
u := User{Name: "transcation"}
477+
if err := tx.Save(&u).Error; err != nil {
478+
t.Errorf("No error should raise")
479+
}
480+
481+
if err := tx.First(&User{}, "name = ?", "transcation").Error; err != nil {
482+
t.Errorf("Should find saved record")
483+
}
484+
485+
return errors.New("the error message")
486+
})
487+
488+
if err.Error() != "the error message" {
489+
t.Errorf("Transaction return error will equal the block returns error")
490+
}
491+
492+
if err := DB.First(&User{}, "name = ?", "transcation").Error; err == nil {
493+
t.Errorf("Should not find record after rollback")
494+
}
495+
496+
// commit
497+
DB.Transaction(func(tx *gorm.DB) error {
498+
u2 := User{Name: "transcation-2"}
499+
if err := tx.Save(&u2).Error; err != nil {
500+
t.Errorf("No error should raise")
501+
}
502+
503+
if err := tx.First(&User{}, "name = ?", "transcation-2").Error; err != nil {
504+
t.Errorf("Should find saved record")
505+
}
506+
return nil
507+
})
508+
509+
if err := DB.First(&User{}, "name = ?", "transcation-2").Error; err != nil {
510+
t.Errorf("Should be able to find committed record")
511+
}
512+
513+
// panic will rollback
514+
DB.Transaction(func(tx *gorm.DB) error {
515+
u3 := User{Name: "transcation-3"}
516+
if err := tx.Save(&u3).Error; err != nil {
517+
t.Errorf("No error should raise")
518+
}
519+
520+
if err := tx.First(&User{}, "name = ?", "transcation-3").Error; err != nil {
521+
t.Errorf("Should find saved record")
522+
}
523+
524+
panic("force panic")
525+
})
526+
527+
if err := DB.First(&User{}, "name = ?", "transcation").Error; err == nil {
528+
t.Errorf("Should not find record after panic rollback")
529+
}
530+
}
531+
472532
func TestTransaction_NoErrorOnRollbackAfterCommit(t *testing.T) {
473533
tx := DB.Begin()
474534
u := User{Name: "transcation"}

0 commit comments

Comments
 (0)