序
本文主要研究一下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 #Isolation_levels.
const (
LevelDefault Isolation Level = 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 Commit ted"
case LevelRepeatableRead:
return "Repeatable Read"
case LevelSnapshot:
return "Snapshot"
case LevelSerializable:
return "Serializable"
case LevelLinearizable:
return "Linearizable"
default:
return "IsolationLevel(" + strconv.Itoa(int(i)) + ")"
}
}
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
- gorm