// Tx returns a copy of the store that runs in the context of the given // transaction. func (s *store) Tx(tx db.Tx) Store { return &store{ Collection: tx.C(s.Collection.Name()), session: &session{ Database: tx, stores: make(map[string]*store), }, } }
// Benchmarking Append() with transactions. func BenchmarkAppendTxUpper(b *testing.B) { var sess db.Database var err error if sess, err = db.Open(Adapter, settings); err != nil { b.Fatal(err) } defer sess.Close() var tx db.Tx if tx, err = sess.Transaction(); err != nil { b.Fatal(err) } var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { b.Fatal(err) } if err = artist.Truncate(); err != nil { b.Fatal(err) } item := struct { Name string `db:"name"` }{"Hayao Miyazaki"} b.ResetTimer() for i := 0; i < b.N; i++ { if _, err = artist.Append(item); err != nil { b.Fatal(err) } } if err = tx.Commit(); err != nil { b.Fatal(err) } }
// Attempts to test database transactions. func TestTransactionsAndRollback(t *testing.T) { var sess db.Database var err error type artistType struct { ID int64 `db:"id,omitempty"` Name string `db:"name"` } if sess, err = db.Open(Adapter, settings); err != nil { t.Fatal(err) } defer sess.Close() // Simple transaction that should not fail. var tx db.Tx if tx, err = sess.Transaction(); err != nil { t.Fatal(err) } var artist db.Collection if artist, err = tx.Collection("artist"); err != nil { t.Fatal(err) } if err = artist.Truncate(); err != nil { t.Fatal(err) } // Simple transaction if _, err = artist.Append(artistType{1, "First"}); err != nil { t.Fatal(err) } if err = tx.Commit(); err != nil { t.Fatal(err) } // Attempt to use the same transaction should fail. if _, err = tx.Collection("artist"); err == nil { t.Fatalf("Illegal, transaction has already been commited.") } // Use another transaction. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) } if artist, err = tx.Collection("artist"); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{2, "Second"}); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{3, "Third"}); err != nil { t.Fatal(err) } // Will fail. if _, err = artist.Append(artistType{1, "Duplicated"}); err == nil { t.Fatal("Should have failed, as we have already inserted ID 1.") } if err = tx.Rollback(); err != nil { t.Fatal(err) } if err = tx.Commit(); err == nil { t.Fatalf("Should have failed, as we've already rolled back.") } // Let's verify we still have one element. if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } var count uint64 if count, err = artist.Find().Count(); err != nil { t.Fatal(err) } if count != 1 { t.Fatalf("Expecting only one element.") } // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) } if artist, err = tx.Collection("artist"); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{2, "Second"}); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{3, "Third"}); err != nil { t.Fatal(err) } // Then rollback for no reason. if err = tx.Rollback(); err != nil { t.Fatal(err) } if err = tx.Commit(); err == nil { t.Fatalf("Should have failed, as we've already rolled back.") } // Let's verify we still have one element. if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } if count, err = artist.Find().Count(); err != nil { t.Fatal(err) } if count != 1 { t.Fatalf("Expecting only one element.") } // Attempt to add some rows. if tx, err = sess.Transaction(); err != nil { t.Fatal(err) } if artist, err = tx.Collection("artist"); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{2, "Second"}); err != nil { t.Fatal(err) } // Won't fail. if _, err = artist.Append(artistType{3, "Third"}); err != nil { t.Fatal(err) } if err = tx.Commit(); err != nil { t.Fatal(err) } if err = tx.Rollback(); err == nil { t.Fatalf("Should have failed, as we've already commited.") } // Let's verify we have 3 rows. if artist, err = sess.Collection("artist"); err != nil { t.Fatal(err) } if count, err = artist.Find().Count(); err != nil { t.Fatal(err) } if count != 3 { t.Fatalf("Expecting 3 elements.") } }