本文主要研究一下gorm的IsolationLevelmysql
/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
/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屬性
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
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
來變動隔離級別
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