123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- package xorm
- import (
- "sync"
- "github.com/xormplus/core"
- )
- const (
- PROPAGATION_REQUIRED = 0 //Support a current transaction; create a new one if none exists.
- PROPAGATION_SUPPORTS = 1 //Support a current transaction; execute non-transactionally if none exists.
- PROPAGATION_MANDATORY = 2 //Support a current transaction; return an error if no current transaction exists.
- PROPAGATION_REQUIRES_NEW = 3 //Create a new transaction, suspending the current transaction if one exists.
- PROPAGATION_NOT_SUPPORTED = 4 //Do not support a current transaction; rather always execute non-transactionally.
- PROPAGATION_NEVER = 5 //Do not support a current transaction; return an error if a current transaction exists.
- PROPAGATION_NESTED = 6 //Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else.
- PROPAGATION_NOT_REQUIRED = 7
- )
- type Transaction struct {
- txSession *Session
- transactionDefinition int
- isNested bool
- savePointID string
- }
- func (transaction *Transaction) TransactionDefinition() int {
- return transaction.transactionDefinition
- }
- func (transaction *Transaction) IsExistingTransaction() bool {
- if transaction.txSession.tx == nil {
- return false
- } else {
- return true
- }
- }
- func (transaction *Transaction) GetSavePointID() string {
- return transaction.savePointID
- }
- func (transaction *Transaction) Session() *Session {
- return transaction.txSession
- }
- func (transaction *Transaction) Do(doFunc func(params ...interface{}), params ...interface{}) {
- if transaction.isNested {
- go doFunc(params...)
- } else {
- doFunc(params...)
- }
- }
- func (transaction *Transaction) WaitForDo(doFunc func(params ...interface{}), params ...interface{}) {
- if transaction.isNested {
- var w sync.WaitGroup
- w.Add(1)
- go func() {
- doFunc(params...)
- w.Done()
- }()
- w.Wait()
- } else {
- doFunc(params...)
- }
- }
- func (session *Session) BeginTrans(transactionDefinition ...int) (*Transaction, error) {
- var tx *Transaction
- if len(transactionDefinition) == 0 {
- tx = session.transaction(PROPAGATION_REQUIRED)
- } else {
- tx = session.transaction(transactionDefinition[0])
- }
- err := tx.BeginTrans()
- if err != nil {
- return nil, err
- }
- return tx, nil
- }
- func (session *Session) transaction(transactionDefinition int) *Transaction {
- if transactionDefinition > 6 || transactionDefinition < 0 {
- return &Transaction{txSession: session, transactionDefinition: PROPAGATION_REQUIRED}
- }
- return &Transaction{txSession: session, transactionDefinition: transactionDefinition}
- }
- // Begin a transaction
- func (transaction *Transaction) BeginTrans() error {
- switch transaction.transactionDefinition {
- case PROPAGATION_REQUIRED:
- if !transaction.IsExistingTransaction() {
- if err := transaction.txSession.Begin(); err != nil {
- return err
- }
- } else {
- if transaction.txSession.currentTransaction != nil {
- transaction.savePointID = transaction.txSession.currentTransaction.savePointID
- }
- transaction.isNested = true
- }
- transaction.txSession.currentTransaction = transaction
- return nil
- case PROPAGATION_SUPPORTS:
- if transaction.IsExistingTransaction() {
- transaction.isNested = true
- if transaction.txSession.currentTransaction != nil {
- transaction.savePointID = transaction.txSession.currentTransaction.savePointID
- }
- transaction.txSession.currentTransaction = transaction
- }
- return nil
- case PROPAGATION_MANDATORY:
- if !transaction.IsExistingTransaction() {
- return ErrNestedTransaction
- } else {
- if transaction.txSession.currentTransaction != nil {
- transaction.savePointID = transaction.txSession.currentTransaction.savePointID
- }
- transaction.isNested = true
- transaction.txSession.currentTransaction = transaction
- }
- return nil
- case PROPAGATION_REQUIRES_NEW:
- transaction.txSession = transaction.txSession.engine.NewSession()
- if err := transaction.txSession.Begin(); err != nil {
- return err
- }
- transaction.isNested = false
- transaction.txSession.currentTransaction = transaction
- return nil
- case PROPAGATION_NOT_SUPPORTED:
- if transaction.IsExistingTransaction() {
- transaction.isNested = true
- transaction.txSession = transaction.txSession.engine.NewSession()
- }
- return nil
- case PROPAGATION_NEVER:
- if transaction.IsExistingTransaction() {
- return ErrNestedTransaction
- }
- return nil
- case PROPAGATION_NESTED:
- if !transaction.IsExistingTransaction() {
- if err := transaction.txSession.Begin(); err != nil {
- return err
- }
- } else {
- transaction.isNested = true
- dbtype := transaction.txSession.engine.Dialect().DBType()
- if dbtype == core.MSSQL {
- transaction.savePointID = "xorm" + NewShortUUID().String()
- } else {
- transaction.savePointID = "xorm" + NewV1().WithoutDashString()
- }
- if err := transaction.SavePoint(transaction.savePointID); err != nil {
- return err
- }
- transaction.txSession.isAutoCommit = false
- transaction.txSession.isCommitedOrRollbacked = false
- transaction.txSession.currentTransaction = transaction
- }
- return nil
- case PROPAGATION_NOT_REQUIRED:
- if transaction.IsExistingTransaction() {
- return ErrNestedTransaction
- }
- if err := transaction.txSession.Begin(); err != nil {
- return err
- }
- return nil
- default:
- return ErrTransactionDefinition
- }
- }
- // Commit When using transaction, Commit will commit all operations.
- func (transaction *Transaction) CommitTrans() error {
- switch transaction.transactionDefinition {
- case PROPAGATION_REQUIRED:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- if !transaction.isNested {
- err := transaction.txSession.Commit()
- if err != nil {
- return err
- }
- }
- return nil
- case PROPAGATION_SUPPORTS:
- if transaction.IsExistingTransaction() {
- if !transaction.isNested {
- err := transaction.txSession.Commit()
- if err != nil {
- return err
- }
- }
- }
- return nil
- case PROPAGATION_MANDATORY:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- if !transaction.isNested {
- err := transaction.txSession.Commit()
- if err != nil {
- return err
- }
- }
- return nil
- case PROPAGATION_REQUIRES_NEW:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- if !transaction.isNested {
- err := transaction.txSession.Commit()
- if err != nil {
- return err
- }
- }
- return nil
- case PROPAGATION_NOT_SUPPORTED:
- if transaction.IsExistingTransaction() {
- return ErrNestedTransaction
- }
- return nil
- case PROPAGATION_NEVER:
- if transaction.IsExistingTransaction() {
- return ErrNestedTransaction
- }
- return nil
- case PROPAGATION_NESTED:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- if !transaction.isNested {
- err := transaction.txSession.Commit()
- if err != nil {
- return err
- }
- } else if transaction.txSession.rollbackSavePointID == transaction.savePointID {
- if err := transaction.RollbackToSavePoint(transaction.savePointID); err != nil {
- transaction.txSession.rollbackSavePointID = ""
- return err
- }
- }
- return nil
- case PROPAGATION_NOT_REQUIRED:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- if !transaction.isNested {
- err := transaction.txSession.Commit()
- if err != nil {
- return err
- }
- } else {
- return ErrNestedTransaction
- }
- return nil
- default:
- return ErrTransactionDefinition
- }
- }
- // Rollback When using transaction, you can rollback if any error
- func (transaction *Transaction) RollbackTrans() error {
- switch transaction.transactionDefinition {
- case PROPAGATION_REQUIRED:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- if transaction.savePointID == "" {
- err := transaction.txSession.Rollback()
- if err != nil {
- return err
- }
- } else {
- transaction.txSession.rollbackSavePointID = transaction.savePointID
- }
- return nil
- case PROPAGATION_SUPPORTS:
- if transaction.IsExistingTransaction() {
- if transaction.savePointID == "" {
- err := transaction.txSession.Rollback()
- if err != nil {
- return err
- }
- } else {
- transaction.txSession.rollbackSavePointID = transaction.savePointID
- }
- return nil
- }
- return nil
- case PROPAGATION_MANDATORY:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- if transaction.savePointID == "" {
- err := transaction.txSession.Rollback()
- if err != nil {
- return err
- }
- } else {
- transaction.txSession.rollbackSavePointID = transaction.savePointID
- }
- return nil
- case PROPAGATION_REQUIRES_NEW:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- err := transaction.txSession.Rollback()
- if err != nil {
- return err
- }
- return nil
- case PROPAGATION_NOT_SUPPORTED:
- if transaction.IsExistingTransaction() {
- return ErrNestedTransaction
- }
- return nil
- case PROPAGATION_NEVER:
- if transaction.IsExistingTransaction() {
- return ErrNestedTransaction
- }
- return nil
- case PROPAGATION_NESTED:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- if transaction.txSession.rollbackSavePointID == transaction.savePointID {
- return nil
- }
- if transaction.isNested {
- if err := transaction.RollbackToSavePoint(transaction.savePointID); err != nil {
- return err
- }
- return nil
- } else {
- err := transaction.txSession.Rollback()
- if err != nil {
- return err
- }
- return nil
- }
- case PROPAGATION_NOT_REQUIRED:
- if !transaction.IsExistingTransaction() {
- return ErrNotInTransaction
- }
- err := transaction.txSession.Rollback()
- if err != nil {
- return err
- }
- return nil
- default:
- return ErrTransactionDefinition
- }
- }
- func (transaction *Transaction) SavePoint(savePointID string) error {
- if transaction.txSession.tx == nil {
- return ErrNotInTransaction
- }
- var lastSQL string
- dbtype := transaction.txSession.engine.Dialect().DBType()
- if dbtype == core.MSSQL {
- lastSQL = "save tran " + savePointID
- } else {
- lastSQL = "SAVEPOINT " + savePointID + ";"
- }
- transaction.txSession.saveLastSQL(lastSQL)
- if _, err := transaction.txSession.tx.Exec(lastSQL); err != nil {
- return err
- }
- return nil
- }
- func (transaction *Transaction) RollbackToSavePoint(savePointID string) error {
- if transaction.txSession.tx == nil {
- return ErrNotInTransaction
- }
- var lastSQL string
- dbtype := transaction.txSession.engine.Dialect().DBType()
- if dbtype == core.MSSQL {
- lastSQL = "rollback tran " + savePointID
- } else {
- lastSQL = "ROLLBACK TO SAVEPOINT " + transaction.savePointID + ";"
- }
- transaction.txSession.saveLastSQL(lastSQL)
- if _, err := transaction.txSession.tx.Exec(lastSQL); err != nil {
- return err
- }
- return nil
- }
|