本文主要研究一下gorm的IsolationLevel

IsolationLevel

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

// 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.go

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.go

// 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.go

// 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.go

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来变更隔离级别。

doc


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...