本文主要研究一下gorm的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
/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属性
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
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
来变更隔离级别
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
来变更隔离级别。