聊聊gorm的IsolationLevel

本文主要研究一下gorm的IsolationLevelmysql

IsolationLevel

/usr/local/go/src/database/sql/sql.gogit

// IsolationLevel is the transaction isolation level used in TxOptions.
type IsolationLevel int

// Various isolation levels that drivers may support in BeginTx.
// If a driver does not support a given isolation level an error may be returned.
//
// See https://en.wikipedia.org/wiki/Isolation_(database_systems)#Isolation_levels.
const (
    LevelDefault IsolationLevel = iota
    LevelReadUncommitted
    LevelReadCommitted
    LevelWriteCommitted
    LevelRepeatableRead
    LevelSnapshot
    LevelSerializable
    LevelLinearizable
)

// String returns the name of the transaction isolation level.
func (i IsolationLevel) String() string {
    switch i {
    case LevelDefault:
        return "Default"
    case LevelReadUncommitted:
        return "Read Uncommitted"
    case LevelReadCommitted:
        return "Read Committed"
    case LevelWriteCommitted:
        return "Write Committed"
    case LevelRepeatableRead:
        return "Repeatable Read"
    case LevelSnapshot:
        return "Snapshot"
    case LevelSerializable:
        return "Serializable"
    case LevelLinearizable:
        return "Linearizable"
    default:
        return "IsolationLevel(" + strconv.Itoa(int(i)) + ")"
    }
}
golang定義了IsolationLevel,分別爲LevelDefault、LevelReadUncommitted、LevelReadCommitted、LevelWriteCommitted、LevelRepeatableRead、LevelSnapshot、LevelSerializable、LevelLinearizable

TxOptions

/usr/local/go/src/database/sql/sql.gogithub

type TxOptions struct {
    // Isolation is the transaction isolation level.
    // If zero, the driver or database's default level is used.
    Isolation IsolationLevel
    ReadOnly  bool
}
sql.TxOptions定義了Isolation、ReadOnly屬性

Transaction

gorm.io/gorm@v1.20.10/finisher_api.gogolang

// Transaction start a transaction as a block, return error will rollback, otherwise to commit.
func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) {
    panicked := true

    if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil {
        // nested transaction
        if !db.DisableNestedTransaction {
            err = db.SavePoint(fmt.Sprintf("sp%p", fc)).Error
            defer func() {
                // Make sure to rollback when panic, Block error or Commit error
                if panicked || err != nil {
                    db.RollbackTo(fmt.Sprintf("sp%p", fc))
                }
            }()
        }

        if err == nil {
            err = fc(db.Session(&Session{}))
        }
    } else {
        tx := db.Begin(opts...)

        defer func() {
            // Make sure to rollback when panic, Block error or Commit error
            if panicked || err != nil {
                tx.Rollback()
            }
        }()

        if err = tx.Error; err == nil {
            err = fc(tx)
        }

        if err == nil {
            err = tx.Commit().Error
        }
    }

    panicked = false
    return
}
gorm的Transaction方法提供了 *sql.TxOptions參數,能夠用於設置Isolation,它最後傳遞給具體的driver

BeginTx

github.com/go-sql-driver/mysql@v1.5.0/connection.gosql

// BeginTx implements driver.ConnBeginTx interface
func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
    if err := mc.watchCancel(ctx); err != nil {
        return nil, err
    }
    defer mc.finish()

    if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
        level, err := mapIsolationLevel(opts.Isolation)
        if err != nil {
            return nil, err
        }
        err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
        if err != nil {
            return nil, err
        }
    }

    return mc.begin(opts.ReadOnly)
}
BeginTx會判斷若指定的隔離級別不是default則會執行mapIsolationLevel映射到mysql支持的隔離級別,而後執行 SET TRANSACTION ISOLATION LEVEL來變動隔離級別

mapIsolationLevel

github.com/go-sql-driver/mysql@v1.5.0/utils.goapi

func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
    switch sql.IsolationLevel(level) {
    case sql.LevelRepeatableRead:
        return "REPEATABLE READ", nil
    case sql.LevelReadCommitted:
        return "READ COMMITTED", nil
    case sql.LevelReadUncommitted:
        return "READ UNCOMMITTED", nil
    case sql.LevelSerializable:
        return "SERIALIZABLE", nil
    default:
        return "", fmt.Errorf("mysql: unsupported isolation level: %v", level)
    }
}
mapIsolationLevel映射golang sql定義的IsolationLevel到mysql支持的隔離級別

小結

golang定義了IsolationLevel,分別爲LevelDefault、LevelReadUncommitted、LevelReadCommitted、LevelWriteCommitted、LevelRepeatableRead、LevelSnapshot、LevelSerializable、LevelLinearizable;gorm的Transaction方法提供了*sql.TxOptions參數,能夠用於設置Isolation,它最後傳遞給具體的driver;BeginTx會判斷若指定的隔離級別不是default則會執行mapIsolationLevel映射到mysql支持的隔離級別,而後執行SET TRANSACTION ISOLATION LEVEL來變動隔離級別。code

doc

相關文章
相關標籤/搜索