mirror of
https://github.com/astaxie/beego.git
synced 2024-11-23 00:50:54 +00:00
support DB.BeginTx of golang 1.8
Signed-off-by: Penghui Liao <liaoishere@gmail.com>
This commit is contained in:
parent
0dff771707
commit
443c77b303
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build go1.8
|
||||||
|
|
||||||
// Package orm provide ORM for MySQL/PostgreSQL/sqlite
|
// Package orm provide ORM for MySQL/PostgreSQL/sqlite
|
||||||
// Simple Usage
|
// Simple Usage
|
||||||
//
|
//
|
||||||
@ -52,6 +54,7 @@
|
|||||||
package orm
|
package orm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -458,11 +461,15 @@ func (o *orm) Using(name string) error {
|
|||||||
|
|
||||||
// begin transaction
|
// begin transaction
|
||||||
func (o *orm) Begin() error {
|
func (o *orm) Begin() error {
|
||||||
|
return o.BeginTx(context.Background(), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *orm) BeginTx(ctx context.Context, opts *sql.TxOptions) error {
|
||||||
if o.isTx {
|
if o.isTx {
|
||||||
return ErrTxHasBegan
|
return ErrTxHasBegan
|
||||||
}
|
}
|
||||||
var tx *sql.Tx
|
var tx *sql.Tx
|
||||||
tx, err := o.db.(txer).Begin()
|
tx, err := o.db.(txer).BeginTx(ctx, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
@ -15,6 +15,7 @@
|
|||||||
package orm
|
package orm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -150,6 +151,13 @@ func (d *dbQueryLog) Begin() (*sql.Tx, error) {
|
|||||||
return tx, err
|
return tx, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dbQueryLog) BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error) {
|
||||||
|
a := time.Now()
|
||||||
|
tx, err := d.db.(txer).BeginTx(ctx, opts)
|
||||||
|
debugLogQueies(d.alias, "db.BeginTx", "START TRANSACTION", a, err)
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
|
||||||
func (d *dbQueryLog) Commit() error {
|
func (d *dbQueryLog) Commit() error {
|
||||||
a := time.Now()
|
a := time.Now()
|
||||||
err := d.db.(txEnder).Commit()
|
err := d.db.(txEnder).Commit()
|
||||||
|
@ -12,10 +12,13 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// +build go1.8
|
||||||
|
|
||||||
package orm
|
package orm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -452,9 +455,9 @@ func TestNullDataTypes(t *testing.T) {
|
|||||||
throwFail(t, AssertIs(*d.Float32Ptr, float32Ptr))
|
throwFail(t, AssertIs(*d.Float32Ptr, float32Ptr))
|
||||||
throwFail(t, AssertIs(*d.Float64Ptr, float64Ptr))
|
throwFail(t, AssertIs(*d.Float64Ptr, float64Ptr))
|
||||||
throwFail(t, AssertIs(*d.DecimalPtr, decimalPtr))
|
throwFail(t, AssertIs(*d.DecimalPtr, decimalPtr))
|
||||||
throwFail(t, AssertIs((*d.TimePtr).Format(testTime), timePtr.Format(testTime)))
|
throwFail(t, AssertIs((*d.TimePtr).UTC().Format(testTime), timePtr.UTC().Format(testTime)))
|
||||||
throwFail(t, AssertIs((*d.DatePtr).Format(testDate), datePtr.Format(testDate)))
|
throwFail(t, AssertIs((*d.DatePtr).UTC().Format(testDate), datePtr.UTC().Format(testDate)))
|
||||||
throwFail(t, AssertIs((*d.DateTimePtr).Format(testDateTime), dateTimePtr.Format(testDateTime)))
|
throwFail(t, AssertIs((*d.DateTimePtr).UTC().Format(testDateTime), dateTimePtr.UTC().Format(testDateTime)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDataCustomTypes(t *testing.T) {
|
func TestDataCustomTypes(t *testing.T) {
|
||||||
@ -1990,6 +1993,66 @@ func TestTransaction(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTransactionIsolationLevel(t *testing.T) {
|
||||||
|
// this test worked when database support transaction isolation level
|
||||||
|
if IsSqlite {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
o1 := NewOrm()
|
||||||
|
o2 := NewOrm()
|
||||||
|
|
||||||
|
// start two transaction with isolation level repeatable read
|
||||||
|
err := o1.BeginTx(context.Background(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
|
||||||
|
throwFail(t, err)
|
||||||
|
err = o2.BeginTx(context.Background(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
|
||||||
|
throwFail(t, err)
|
||||||
|
|
||||||
|
// o1 insert tag
|
||||||
|
var tag Tag
|
||||||
|
tag.Name = "test-transaction"
|
||||||
|
id, err := o1.Insert(&tag)
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(id > 0, true))
|
||||||
|
|
||||||
|
// o2 query tag table, no result
|
||||||
|
num, err := o2.QueryTable("tag").Filter("name", "test-transaction").Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 0))
|
||||||
|
|
||||||
|
// o1 commit
|
||||||
|
o1.Commit()
|
||||||
|
|
||||||
|
// o2 query tag table, still no result
|
||||||
|
num, err = o2.QueryTable("tag").Filter("name", "test-transaction").Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 0))
|
||||||
|
|
||||||
|
// o2 commit and query tag table, get the result
|
||||||
|
o2.Commit()
|
||||||
|
num, err = o2.QueryTable("tag").Filter("name", "test-transaction").Count()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
|
||||||
|
num, err = o1.QueryTable("tag").Filter("name", "test-transaction").Delete()
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(num, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBeginTxWithContextCanceled(t *testing.T) {
|
||||||
|
o := NewOrm()
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
o.BeginTx(ctx, nil)
|
||||||
|
id, err := o.Insert(&Tag{Name: "test-context"})
|
||||||
|
throwFail(t, err)
|
||||||
|
throwFail(t, AssertIs(id > 0, true))
|
||||||
|
|
||||||
|
// cancel the context before commit to make it error
|
||||||
|
cancel()
|
||||||
|
err = o.Commit()
|
||||||
|
throwFail(t, AssertIs(err, context.Canceled))
|
||||||
|
}
|
||||||
|
|
||||||
func TestReadOrCreate(t *testing.T) {
|
func TestReadOrCreate(t *testing.T) {
|
||||||
u := &User{
|
u := &User{
|
||||||
UserName: "Kyle",
|
UserName: "Kyle",
|
||||||
@ -2260,6 +2323,7 @@ func TestIgnoreCaseTag(t *testing.T) {
|
|||||||
throwFail(t, AssertIs(info.fields.GetByName("Name02").column, "Name"))
|
throwFail(t, AssertIs(info.fields.GetByName("Name02").column, "Name"))
|
||||||
throwFail(t, AssertIs(info.fields.GetByName("Name03").column, "name"))
|
throwFail(t, AssertIs(info.fields.GetByName("Name03").column, "name"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInsertOrUpdate(t *testing.T) {
|
func TestInsertOrUpdate(t *testing.T) {
|
||||||
RegisterModel(new(User))
|
RegisterModel(new(User))
|
||||||
user := User{UserName: "unique_username133", Status: 1, Password: "o"}
|
user := User{UserName: "unique_username133", Status: 1, Password: "o"}
|
||||||
|
13
orm/types.go
13
orm/types.go
@ -15,6 +15,7 @@
|
|||||||
package orm
|
package orm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"time"
|
||||||
@ -106,6 +107,17 @@ type Ormer interface {
|
|||||||
// ...
|
// ...
|
||||||
// err = o.Rollback()
|
// err = o.Rollback()
|
||||||
Begin() error
|
Begin() error
|
||||||
|
// begin transaction with provided context and option
|
||||||
|
// the provided context is used until the transaction is committed or rolled back.
|
||||||
|
// if the context is canceled, the transaction will be rolled back.
|
||||||
|
// the provided TxOptions is optional and may be nil if defaults should be used.
|
||||||
|
// if a non-default isolation level is used that the driver doesn't support, an error will be returned.
|
||||||
|
// for example:
|
||||||
|
// o := NewOrm()
|
||||||
|
// err := o.BeginTx(context.Background(), &sql.TxOptions{Isolation: sql.LevelRepeatableRead})
|
||||||
|
// ...
|
||||||
|
// err = o.Rollback()
|
||||||
|
BeginTx(ctx context.Context, opts *sql.TxOptions) error
|
||||||
// commit transaction
|
// commit transaction
|
||||||
Commit() error
|
Commit() error
|
||||||
// rollback transaction
|
// rollback transaction
|
||||||
@ -401,6 +413,7 @@ type dbQuerier interface {
|
|||||||
// transaction beginner
|
// transaction beginner
|
||||||
type txer interface {
|
type txer interface {
|
||||||
Begin() (*sql.Tx, error)
|
Begin() (*sql.Tx, error)
|
||||||
|
BeginTx(ctx context.Context, opts *sql.TxOptions) (*sql.Tx, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// transaction ending
|
// transaction ending
|
||||||
|
Loading…
Reference in New Issue
Block a user