From a87a321780307f3816bb87fd2c10552f206c0ac0 Mon Sep 17 00:00:00 2001 From: cwww3 <2239354893@qq.com> Date: Thu, 4 Jul 2024 12:45:45 +0800 Subject: [PATCH] Site updated: 2024-07-04 12:45:45 --- 2021/05/06/mysql-index2/index.html | 6 ++-- 2022/07/02/gorm/index.html | 19 +++++------ atom.xml | 6 ++-- css/main.css | 2 +- page/2/index.html | 4 +-- sitemap.xml | 54 +++++++++++++++--------------- 6 files changed, 44 insertions(+), 47 deletions(-) diff --git a/2021/05/06/mysql-index2/index.html b/2021/05/06/mysql-index2/index.html index 76f4fe0a..f1e4f2f7 100644 --- a/2021/05/06/mysql-index2/index.html +++ b/2021/05/06/mysql-index2/index.html @@ -285,14 +285,14 @@

zhangssxyz@xxx.com’的这条记录,取得 ID2 的值; +
  • 从 index1 索引树找到满足索引值是’zhangssxyz@xxx.com’的这条记录,取得 ID2 的值;
  • 到主键上查到主键值是 ID2 的行,判断 email 的值是正确的,将这行记录加入结果集;
  • -
  • 取 index1 索引树上刚刚查到的位置的下一条记录,发现已经不满足 email=‘zhangssxyz@xxx.com’的条件了,循环结束。
  • +
  • 取 index1 索引树上刚刚查到的位置的下一条记录,发现已经不满足 email=‘zhangssxyz@xxx.com’的条件了,循环结束。
  • 如果使用的是 index2

    1. 从 index2 索引树找到满足索引值是’zhangs’的记录,找到的第一个是 ID1;
    2. -
    3. 到主键上查到主键值是 ID1 的行,判断出 email 的值不是’zhangssxyz@xxx.com’,这行记录丢弃;
    4. +
    5. 到主键上查到主键值是 ID1 的行,判断出 email 的值不是’zhangssxyz@xxx.com’,这行记录丢弃;
    6. 取 index2 上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出 ID2,再到 ID 索引上取整行然后判断,这次值对了,将这行记录加入结果集;
    7. 重复上一步,直到在 idxe2 上取到的值不是’zhangs’时,循环结束。
    diff --git a/2022/07/02/gorm/index.html b/2022/07/02/gorm/index.html index dbb53f2c..85f70fd0 100644 --- a/2022/07/02/gorm/index.html +++ b/2022/07/02/gorm/index.html @@ -20,15 +20,15 @@ var CONFIG = {"hostname":"cwww3.github.io","root":"/","scheme":"Muse","version":"7.8.0","exturl":false,"sidebar":{"position":"right","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}}; - + - + - + @@ -188,7 +188,7 @@

    更新于 - + @@ -216,21 +216,18 @@

    -

    GORM源码浅析

    连接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    // gorm 连接数据库
    func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
    // 全局配置
    config := &Config{}

    ...

    // 加载配置
    for _, opt := range opts {
    if opt != nil {
    if applyErr := opt.Apply(config); applyErr != nil {
    return nil, applyErr
    }
    defer func(opt Option) {
    if errr := opt.AfterInitialize(db); errr != nil {
    err = errr
    }
    }(opt)
    }
    }

    // 时间精度配置 默认毫秒
    if d, ok := dialector.(interface{ Apply(*Config) error }); ok {
    if err = d.Apply(config); err != nil {
    return
    }
    }


    // 注册query/create..等操作执行时所需要调用的函数
    // gorm:query -> gorm:preload -> gorm:after_query
    // 对不同版本的数据库做相应的约束配置
    // 调用sql.Open()初始化连接池
    db.callbacks = initializeCallbacks(db)
    if config.Dialector != nil {
    err = config.Dialector.Initialize(db)
    }

    ...

    // clone=1
    db = &DB{Config: config, clone: 1}

    // 在执行sql前后,相关的信息都会存在其中
    db.Statement = &Statement{
    DB: db,
    ConnPool: db.ConnPool,
    Context: context.Background(),
    Clauses: map[string]clause.Clause{},
    }

    // 连接时,自动会进行ping操作
    if err == nil && !config.DisableAutomaticPing {
    if pinger, ok := db.ConnPool.(interface{ Ping() error }); ok {
    err = pinger.Ping()
    }
    }

    if err != nil {
    config.Logger.Error(context.Background(), "failed to initialize database, got error %v", err)
    }

    return
    }

    +

    GORM 源码浅析

    连接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    // gorm 连接数据库
    func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
    // 全局配置
    config := &Config{}

    ...

    // 加载配置
    for _, opt := range opts {
    if opt != nil {
    if applyErr := opt.Apply(config); applyErr != nil {
    return nil, applyErr
    }
    defer func(opt Option) {
    if errr := opt.AfterInitialize(db); errr != nil {
    err = errr
    }
    }(opt)
    }
    }

    // 时间精度配置 默认毫秒
    if d, ok := dialector.(interface{ Apply(*Config) error }); ok {
    if err = d.Apply(config); err != nil {
    return
    }
    }


    // 注册query/create..等操作执行时所需要调用的函数
    // gorm:query -> gorm:preload -> gorm:after_query
    // 对不同版本的数据库做相应的约束配置
    // 调用sql.Open()初始化连接池
    db.callbacks = initializeCallbacks(db)
    if config.Dialector != nil {
    err = config.Dialector.Initialize(db)
    }

    ...

    // clone=1
    db = &DB{Config: config, clone: 1}

    // 在执行sql前后,相关的信息都会存在其中
    db.Statement = &Statement{
    DB: db,
    ConnPool: db.ConnPool,
    Context: context.Background(),
    Clauses: map[string]clause.Clause{},
    }

    // 连接时,自动会进行ping操作
    if err == nil && !config.DisableAutomaticPing {
    if pinger, ok := db.ConnPool.(interface{ Ping() error }); ok {
    err = pinger.Ping()
    }
    }

    if err != nil {
    config.Logger.Error(context.Background(), "failed to initialize database, got error %v", err)
    }

    return
    }

    -

    Session

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    // Session create new db session 可覆盖全局配置
    func (db *DB) Session(config *Session) *DB {
    var (
    txConfig = *db.Config
    tx = &DB{
    Config: &txConfig,
    Statement: db.Statement, // 直接赋值原db的statement
    Error: db.Error,
    clone: 1, // clone = 1
    }
    )

    // 对全局配置进行覆盖
    if config.CreateBatchSize > 0 {
    tx.Config.CreateBatchSize = config.CreateBatchSize
    }

    if config.SkipDefaultTransaction {
    tx.Config.SkipDefaultTransaction = true
    }

    if config.AllowGlobalUpdate {
    txConfig.AllowGlobalUpdate = true
    }

    if config.FullSaveAssociations {
    txConfig.FullSaveAssociations = true
    }

    // 如果条件true 会对原db的statement进行深拷贝(并发安全)
    // 如果不进行clone,原db和新db使用的是同一个statement
    // 在分别执行sql后,信息都会存于同一个statement中,相互影响
    if config.Context != nil || config.PrepareStmt || config.SkipHooks {
    tx.Statement = tx.Statement.clone()
    tx.Statement.DB = tx
    }

    if config.Context != nil {
    tx.Statement.Context = config.Context
    }

    ...

    if config.DisableNestedTransaction {
    txConfig.DisableNestedTransaction = true
    }

    // newDB=true clone=1
    // newDB=false clone=2
    // clone值的影响在getInstance()中体现
    if !config.NewDB {
    tx.clone = 2
    }

    if config.DryRun {
    tx.Config.DryRun = true
    }

    if config.QueryFields {
    tx.Config.QueryFields = true
    }

    if config.Logger != nil {
    tx.Config.Logger = config.Logger
    }

    if config.NowFunc != nil {
    tx.Config.NowFunc = config.NowFunc
    }

    if config.Initialized {
    tx = tx.getInstance()
    }

    return tx
    }


    +

    Session

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    // Session create new db session 可覆盖全局配置
    func (db *DB) Session(config *Session) *DB {
    var (
    txConfig = *db.Config
    tx = &DB{
    Config: &txConfig,
    Statement: db.Statement, // 直接赋值原db的statement
    Error: db.Error,
    clone: 1, // clone = 1
    }
    )

    // 对全局配置进行覆盖
    if config.CreateBatchSize > 0 {
    tx.Config.CreateBatchSize = config.CreateBatchSize
    }

    if config.SkipDefaultTransaction {
    tx.Config.SkipDefaultTransaction = true
    }

    if config.AllowGlobalUpdate {
    txConfig.AllowGlobalUpdate = true
    }

    if config.FullSaveAssociations {
    txConfig.FullSaveAssociations = true
    }

    // 如果条件true 会对原db的statement进行深拷贝(并发安全)
    // 如果不进行clone,原db和新db使用的是同一个statement
    // 在分别执行sql后,信息都会存于同一个statement中,相互影响
    if config.Context != nil || config.PrepareStmt || config.SkipHooks {
    tx.Statement = tx.Statement.clone()
    tx.Statement.DB = tx
    }

    if config.Context != nil {
    tx.Statement.Context = config.Context
    }

    ...

    if config.DisableNestedTransaction {
    txConfig.DisableNestedTransaction = true
    }

    // newDB=true clone=1
    // newDB=false clone=2
    // clone值的影响在getInstance()中体现
    if !config.NewDB {
    tx.clone = 2
    }

    if config.DryRun {
    tx.Config.DryRun = true
    }

    if config.QueryFields {
    tx.Config.QueryFields = true
    }

    if config.Logger != nil {
    tx.Config.Logger = config.Logger
    }

    if config.NowFunc != nil {
    tx.Config.NowFunc = config.NowFunc
    }

    if config.Initialized {
    tx = tx.getInstance()
    }

    return tx
    }


    -

    getInstance

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    // 在执行大部分语句之前都会调用该方法
    // Model() Where() Order() Find() ...
    func (db *DB) getInstance() *DB {
    // 根据clone的值,做相应的处理

    // 如果db=1,会将statement清空,原先设置的条件(比如where order...)都会清除
    // 如果db=2, 会将statement进行深拷贝,原先的条件保留,但是新老db互不影响()
    // 如果clone=0,直接返回,不做任何操作
    // 做一些build(拼接)操作,比如执行Where(),Order()等操作时,直接使用原db即可,不需要对statement进行拷贝或清除

    if db.clone > 0 {
    tx := &DB{Config: db.Config, Error: db.Error}

    if db.clone == 1 {
    // clone with new statement
    tx.Statement = &Statement{
    DB: tx,
    ConnPool: db.Statement.ConnPool,
    Context: db.Statement.Context,
    Clauses: map[string]clause.Clause{},
    Vars: make([]interface{}, 0, 8),
    }
    } else {
    // with clone statement
    tx.Statement = db.Statement.clone()
    tx.Statement.DB = tx
    }

    return tx
    }

    return db
    }
    +

    getInstance

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    // 在执行大部分语句之前都会调用该方法
    // Model() Where() Order() Find() ...
    func (db *DB) getInstance() *DB {
    // 根据clone的值,做相应的处理

    // 如果clone=1,会将statement清空,原先设置的条件(比如where order...)都会清除
    // 如果clone=2, 会将statement进行深拷贝,原先的条件保留,但是新老db互不影响()
    // 如果clone=0,直接返回,不做任何操作
    // 做一些build(拼接)操作,比如执行Where(),Order()等操作时,直接使用原db即可,不需要对statement进行拷贝或清除

    if db.clone > 0 {
    tx := &DB{Config: db.Config, Error: db.Error}

    if db.clone == 1 {
    // clone with new statement
    tx.Statement = &Statement{
    DB: tx,
    ConnPool: db.Statement.ConnPool,
    Context: db.Statement.Context,
    Clauses: map[string]clause.Clause{},
    Vars: make([]interface{}, 0, 8),
    }
    } else {
    // with clone statement
    tx.Statement = db.Statement.clone()
    tx.Statement.DB = tx
    }

    return tx
    }

    return db
    }

    Tx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    // 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
    // 嵌套事务会进入该分支,原理是一个事务可以分为多个段,用户可以将事务回滚到指定的段,而不是整个事务
    // https://dotnettutorials.net/lesson/savepoint-in-mysql/
    if !db.DisableNestedTransaction {
    err = db.SavePoint(fmt.Sprintf("sp%p", fc)).Error
    if err != nil {
    return
    }

    defer func() {
    // Make sure to rollback when panic, Block error or Commit error
    if panicked || err != nil {
    db.RollbackTo(fmt.Sprintf("sp%p", fc))
    }
    }()
    }
    err = fc(db.Session(&Session{NewDB: db.clone == 1}))
    } else {
    // 非嵌套事务 开启事务
    tx := db.Begin(opts...)
    if tx.Error != nil {
    return tx.Error
    }

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

    if err = fc(tx); err == nil {
    panicked = false
    // commit 事务
    return tx.Commit().Error
    }
    }

    panicked = false
    return
    }

    嵌套事务

    1
    2
    3
    4
    5
    6
    db.Transaction(func(tx *gorm.DB) error {
    tx.Transaction(func(tx2 *gorm.DB) error {
    return nil
    })
    return nil
    })
    - - -
    @@ -329,7 +326,7 @@

    -
    +
    diff --git a/atom.xml b/atom.xml index 6f660b6b..d16b1037 100644 --- a/atom.xml +++ b/atom.xml @@ -245,12 +245,12 @@ flowchart LR https://cwww3.github.io/2022/07/02/gorm/ 2022-07-02T14:51:13.000Z - 2024-07-04T04:43:30.944Z + 2024-07-04T04:45:40.784Z - GORM源码浅析

    连接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    // gorm 连接数据库
    func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
    // 全局配置
    config := &Config{}

    ...

    // 加载配置
    for _, opt := range opts {
    if opt != nil {
    if applyErr := opt.Apply(config); applyErr != nil {
    return nil, applyErr
    }
    defer func(opt Option) {
    if errr := opt.AfterInitialize(db); errr != nil {
    err = errr
    }
    }(opt)
    }
    }

    // 时间精度配置 默认毫秒
    if d, ok := dialector.(interface{ Apply(*Config) error }); ok {
    if err = d.Apply(config); err != nil {
    return
    }
    }


    // 注册query/create..等操作执行时所需要调用的函数
    // gorm:query -> gorm:preload -> gorm:after_query
    // 对不同版本的数据库做相应的约束配置
    // 调用sql.Open()初始化连接池
    db.callbacks = initializeCallbacks(db)
    if config.Dialector != nil {
    err = config.Dialector.Initialize(db)
    }

    ...

    // clone=1
    db = &DB{Config: config, clone: 1}

    // 在执行sql前后,相关的信息都会存在其中
    db.Statement = &Statement{
    DB: db,
    ConnPool: db.ConnPool,
    Context: context.Background(),
    Clauses: map[string]clause.Clause{},
    }

    // 连接时,自动会进行ping操作
    if err == nil && !config.DisableAutomaticPing {
    if pinger, ok := db.ConnPool.(interface{ Ping() error }); ok {
    err = pinger.Ping()
    }
    }

    if err != nil {
    config.Logger.Error(context.Background(), "failed to initialize database, got error %v", err)
    }

    return
    }

    Session

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    // Session create new db session 可覆盖全局配置
    func (db *DB) Session(config *Session) *DB {
    var (
    txConfig = *db.Config
    tx = &DB{
    Config: &txConfig,
    Statement: db.Statement, // 直接赋值原db的statement
    Error: db.Error,
    clone: 1, // clone = 1
    }
    )

    // 对全局配置进行覆盖
    if config.CreateBatchSize > 0 {
    tx.Config.CreateBatchSize = config.CreateBatchSize
    }

    if config.SkipDefaultTransaction {
    tx.Config.SkipDefaultTransaction = true
    }

    if config.AllowGlobalUpdate {
    txConfig.AllowGlobalUpdate = true
    }

    if config.FullSaveAssociations {
    txConfig.FullSaveAssociations = true
    }

    // 如果条件true 会对原db的statement进行深拷贝(并发安全)
    // 如果不进行clone,原db和新db使用的是同一个statement
    // 在分别执行sql后,信息都会存于同一个statement中,相互影响
    if config.Context != nil || config.PrepareStmt || config.SkipHooks {
    tx.Statement = tx.Statement.clone()
    tx.Statement.DB = tx
    }

    if config.Context != nil {
    tx.Statement.Context = config.Context
    }

    ...

    if config.DisableNestedTransaction {
    txConfig.DisableNestedTransaction = true
    }

    // newDB=true clone=1
    // newDB=false clone=2
    // clone值的影响在getInstance()中体现
    if !config.NewDB {
    tx.clone = 2
    }

    if config.DryRun {
    tx.Config.DryRun = true
    }

    if config.QueryFields {
    tx.Config.QueryFields = true
    }

    if config.Logger != nil {
    tx.Config.Logger = config.Logger
    }

    if config.NowFunc != nil {
    tx.Config.NowFunc = config.NowFunc
    }

    if config.Initialized {
    tx = tx.getInstance()
    }

    return tx
    }


    getInstance

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    // 在执行大部分语句之前都会调用该方法
    // Model() Where() Order() Find() ...
    func (db *DB) getInstance() *DB {
    // 根据clone的值,做相应的处理

    // 如果db=1,会将statement清空,原先设置的条件(比如where order...)都会清除
    // 如果db=2, 会将statement进行深拷贝,原先的条件保留,但是新老db互不影响()
    // 如果clone=0,直接返回,不做任何操作
    // 做一些build(拼接)操作,比如执行Where(),Order()等操作时,直接使用原db即可,不需要对statement进行拷贝或清除

    if db.clone > 0 {
    tx := &DB{Config: db.Config, Error: db.Error}

    if db.clone == 1 {
    // clone with new statement
    tx.Statement = &Statement{
    DB: tx,
    ConnPool: db.Statement.ConnPool,
    Context: db.Statement.Context,
    Clauses: map[string]clause.Clause{},
    Vars: make([]interface{}, 0, 8),
    }
    } else {
    // with clone statement
    tx.Statement = db.Statement.clone()
    tx.Statement.DB = tx
    }

    return tx
    }

    return db
    }

    Tx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    // 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
    // 嵌套事务会进入该分支,原理是一个事务可以分为多个段,用户可以将事务回滚到指定的段,而不是整个事务
    // https://dotnettutorials.net/lesson/savepoint-in-mysql/
    if !db.DisableNestedTransaction {
    err = db.SavePoint(fmt.Sprintf("sp%p", fc)).Error
    if err != nil {
    return
    }

    defer func() {
    // Make sure to rollback when panic, Block error or Commit error
    if panicked || err != nil {
    db.RollbackTo(fmt.Sprintf("sp%p", fc))
    }
    }()
    }
    err = fc(db.Session(&Session{NewDB: db.clone == 1}))
    } else {
    // 非嵌套事务 开启事务
    tx := db.Begin(opts...)
    if tx.Error != nil {
    return tx.Error
    }

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

    if err = fc(tx); err == nil {
    panicked = false
    // commit 事务
    return tx.Commit().Error
    }
    }

    panicked = false
    return
    }

    嵌套事务

    1
    2
    3
    4
    5
    6
    db.Transaction(func(tx *gorm.DB) error {
    tx.Transaction(func(tx2 *gorm.DB) error {
    return nil
    })
    return nil
    })
    ]]> + GORM 源码浅析

    连接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    // gorm 连接数据库
    func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
    // 全局配置
    config := &Config{}

    ...

    // 加载配置
    for _, opt := range opts {
    if opt != nil {
    if applyErr := opt.Apply(config); applyErr != nil {
    return nil, applyErr
    }
    defer func(opt Option) {
    if errr := opt.AfterInitialize(db); errr != nil {
    err = errr
    }
    }(opt)
    }
    }

    // 时间精度配置 默认毫秒
    if d, ok := dialector.(interface{ Apply(*Config) error }); ok {
    if err = d.Apply(config); err != nil {
    return
    }
    }


    // 注册query/create..等操作执行时所需要调用的函数
    // gorm:query -> gorm:preload -> gorm:after_query
    // 对不同版本的数据库做相应的约束配置
    // 调用sql.Open()初始化连接池
    db.callbacks = initializeCallbacks(db)
    if config.Dialector != nil {
    err = config.Dialector.Initialize(db)
    }

    ...

    // clone=1
    db = &DB{Config: config, clone: 1}

    // 在执行sql前后,相关的信息都会存在其中
    db.Statement = &Statement{
    DB: db,
    ConnPool: db.ConnPool,
    Context: context.Background(),
    Clauses: map[string]clause.Clause{},
    }

    // 连接时,自动会进行ping操作
    if err == nil && !config.DisableAutomaticPing {
    if pinger, ok := db.ConnPool.(interface{ Ping() error }); ok {
    err = pinger.Ping()
    }
    }

    if err != nil {
    config.Logger.Error(context.Background(), "failed to initialize database, got error %v", err)
    }

    return
    }

    Session

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    // Session create new db session 可覆盖全局配置
    func (db *DB) Session(config *Session) *DB {
    var (
    txConfig = *db.Config
    tx = &DB{
    Config: &txConfig,
    Statement: db.Statement, // 直接赋值原db的statement
    Error: db.Error,
    clone: 1, // clone = 1
    }
    )

    // 对全局配置进行覆盖
    if config.CreateBatchSize > 0 {
    tx.Config.CreateBatchSize = config.CreateBatchSize
    }

    if config.SkipDefaultTransaction {
    tx.Config.SkipDefaultTransaction = true
    }

    if config.AllowGlobalUpdate {
    txConfig.AllowGlobalUpdate = true
    }

    if config.FullSaveAssociations {
    txConfig.FullSaveAssociations = true
    }

    // 如果条件true 会对原db的statement进行深拷贝(并发安全)
    // 如果不进行clone,原db和新db使用的是同一个statement
    // 在分别执行sql后,信息都会存于同一个statement中,相互影响
    if config.Context != nil || config.PrepareStmt || config.SkipHooks {
    tx.Statement = tx.Statement.clone()
    tx.Statement.DB = tx
    }

    if config.Context != nil {
    tx.Statement.Context = config.Context
    }

    ...

    if config.DisableNestedTransaction {
    txConfig.DisableNestedTransaction = true
    }

    // newDB=true clone=1
    // newDB=false clone=2
    // clone值的影响在getInstance()中体现
    if !config.NewDB {
    tx.clone = 2
    }

    if config.DryRun {
    tx.Config.DryRun = true
    }

    if config.QueryFields {
    tx.Config.QueryFields = true
    }

    if config.Logger != nil {
    tx.Config.Logger = config.Logger
    }

    if config.NowFunc != nil {
    tx.Config.NowFunc = config.NowFunc
    }

    if config.Initialized {
    tx = tx.getInstance()
    }

    return tx
    }


    getInstance

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34

    // 在执行大部分语句之前都会调用该方法
    // Model() Where() Order() Find() ...
    func (db *DB) getInstance() *DB {
    // 根据clone的值,做相应的处理

    // 如果clone=1,会将statement清空,原先设置的条件(比如where order...)都会清除
    // 如果clone=2, 会将statement进行深拷贝,原先的条件保留,但是新老db互不影响()
    // 如果clone=0,直接返回,不做任何操作
    // 做一些build(拼接)操作,比如执行Where(),Order()等操作时,直接使用原db即可,不需要对statement进行拷贝或清除

    if db.clone > 0 {
    tx := &DB{Config: db.Config, Error: db.Error}

    if db.clone == 1 {
    // clone with new statement
    tx.Statement = &Statement{
    DB: tx,
    ConnPool: db.Statement.ConnPool,
    Context: db.Statement.Context,
    Clauses: map[string]clause.Clause{},
    Vars: make([]interface{}, 0, 8),
    }
    } else {
    // with clone statement
    tx.Statement = db.Statement.clone()
    tx.Statement.DB = tx
    }

    return tx
    }

    return db
    }

    Tx

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    // 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
    // 嵌套事务会进入该分支,原理是一个事务可以分为多个段,用户可以将事务回滚到指定的段,而不是整个事务
    // https://dotnettutorials.net/lesson/savepoint-in-mysql/
    if !db.DisableNestedTransaction {
    err = db.SavePoint(fmt.Sprintf("sp%p", fc)).Error
    if err != nil {
    return
    }

    defer func() {
    // Make sure to rollback when panic, Block error or Commit error
    if panicked || err != nil {
    db.RollbackTo(fmt.Sprintf("sp%p", fc))
    }
    }()
    }
    err = fc(db.Session(&Session{NewDB: db.clone == 1}))
    } else {
    // 非嵌套事务 开启事务
    tx := db.Begin(opts...)
    if tx.Error != nil {
    return tx.Error
    }

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

    if err = fc(tx); err == nil {
    panicked = false
    // commit 事务
    return tx.Commit().Error
    }
    }

    panicked = false
    return
    }

    嵌套事务

    1
    2
    3
    4
    5
    6
    db.Transaction(func(tx *gorm.DB) error {
    tx.Transaction(func(tx2 *gorm.DB) error {
    return nil
    })
    return nil
    })
    ]]>
    - <h2 id="GORM源码浅析"><a href="#GORM源码浅析" class="headerlink" title="GORM源码浅析"></a>GORM源码浅析</h2><h3 id="连接"><a href="#连接" class="headerlink" title="连接"></a>连接</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// gorm 连接数据库</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Open</span><span class="params">(dialector Dialector, opts ...Option)</span> <span class="params">(db *DB, err error)</span></span> &#123;</span><br><span class="line"> <span class="comment">// 全局配置</span></span><br><span class="line"> config := &amp;Config&#123;&#125;</span><br><span class="line"> </span><br><span class="line"> ...</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 加载配置</span></span><br><span class="line"> <span class="keyword">for</span> _, opt := <span class="keyword">range</span> opts &#123;</span><br><span class="line"> <span class="keyword">if</span> opt != <span class="literal">nil</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> applyErr := opt.Apply(config); applyErr != <span class="literal">nil</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, applyErr</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">(opt Option)</span></span> &#123;</span><br><span class="line"> <span class="keyword">if</span> errr := opt.AfterInitialize(db); errr != <span class="literal">nil</span> &#123;</span><br><span class="line"> err = errr</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;(opt)</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// 时间精度配置 默认毫秒</span></span><br><span class="line"> <span class="keyword">if</span> d, ok := dialector.(<span class="keyword">interface</span>&#123; Apply(*Config) error &#125;); ok &#123;</span><br><span class="line"> <span class="keyword">if</span> err = d.Apply(config); err != <span class="literal">nil</span> &#123;</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 注册query/create..等操作执行时所需要调用的函数</span></span><br><span class="line"> <span class="comment">// gorm:query -&gt; gorm:preload -&gt; gorm:after_query</span></span><br><span class="line"> <span class="comment">// 对不同版本的数据库做相应的约束配置</span></span><br><span class="line"> <span class="comment">// 调用sql.Open()初始化连接池</span></span><br><span class="line"> db.callbacks = initializeCallbacks(db)</span><br><span class="line"> <span class="keyword">if</span> config.Dialector != <span class="literal">nil</span> &#123;</span><br><span class="line"> err = config.Dialector.Initialize(db)</span><br><span class="line"> &#125;</span><br><span class="line"> </span><br><span class="line"> ...</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// clone=1</span></span><br><span class="line"> db = &amp;DB&#123;Config: config, clone: <span class="number">1</span>&#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在执行sql前后,相关的信息都会存在其中</span></span><br><span class="line"> db.Statement = &amp;Statement&#123;</span><br><span class="line"> DB: db,</span><br><span class="line"> ConnPool: db.ConnPool,</span><br><span class="line"> Context: context.Background(),</span><br><span class="line"> Clauses: <span class="keyword">map</span>[<span class="keyword">string</span>]clause.Clause&#123;&#125;,</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 连接时,自动会进行ping操作</span></span><br><span class="line"> <span class="keyword">if</span> err == <span class="literal">nil</span> &amp;&amp; !config.DisableAutomaticPing &#123;</span><br><span class="line"> <span class="keyword">if</span> pinger, ok := db.ConnPool.(<span class="keyword">interface</span>&#123; Ping() error &#125;); ok &#123;</span><br><span class="line"> err = pinger.Ping()</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"> config.Logger.Error(context.Background(), <span class="string">&quot;failed to initialize database, got error %v&quot;</span>, err)</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure> + <h2 id="GORM-源码浅析"><a href="#GORM-源码浅析" class="headerlink" title="GORM 源码浅析"></a>GORM 源码浅析</h2><h3 id="连接"><a href="#连接" class="headerlink" title="连接"></a>连接</h3><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// gorm 连接数据库</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">Open</span><span class="params">(dialector Dialector, opts ...Option)</span> <span class="params">(db *DB, err error)</span></span> &#123;</span><br><span class="line"> <span class="comment">// 全局配置</span></span><br><span class="line"> config := &amp;Config&#123;&#125;</span><br><span class="line"></span><br><span class="line"> ...</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 加载配置</span></span><br><span class="line"> <span class="keyword">for</span> _, opt := <span class="keyword">range</span> opts &#123;</span><br><span class="line"> <span class="keyword">if</span> opt != <span class="literal">nil</span> &#123;</span><br><span class="line"> <span class="keyword">if</span> applyErr := opt.Apply(config); applyErr != <span class="literal">nil</span> &#123;</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">nil</span>, applyErr</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">defer</span> <span class="function"><span class="keyword">func</span><span class="params">(opt Option)</span></span> &#123;</span><br><span class="line"> <span class="keyword">if</span> errr := opt.AfterInitialize(db); errr != <span class="literal">nil</span> &#123;</span><br><span class="line"> err = errr</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;(opt)</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 时间精度配置 默认毫秒</span></span><br><span class="line"> <span class="keyword">if</span> d, ok := dialector.(<span class="keyword">interface</span>&#123; Apply(*Config) error &#125;); ok &#123;</span><br><span class="line"> <span class="keyword">if</span> err = d.Apply(config); err != <span class="literal">nil</span> &#123;</span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">// 注册query/create..等操作执行时所需要调用的函数</span></span><br><span class="line"> <span class="comment">// gorm:query -&gt; gorm:preload -&gt; gorm:after_query</span></span><br><span class="line"> <span class="comment">// 对不同版本的数据库做相应的约束配置</span></span><br><span class="line"> <span class="comment">// 调用sql.Open()初始化连接池</span></span><br><span class="line"> db.callbacks = initializeCallbacks(db)</span><br><span class="line"> <span class="keyword">if</span> config.Dialector != <span class="literal">nil</span> &#123;</span><br><span class="line"> err = config.Dialector.Initialize(db)</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> ...</span><br><span class="line"></span><br><span class="line"> <span class="comment">// clone=1</span></span><br><span class="line"> db = &amp;DB&#123;Config: config, clone: <span class="number">1</span>&#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 在执行sql前后,相关的信息都会存在其中</span></span><br><span class="line"> db.Statement = &amp;Statement&#123;</span><br><span class="line"> DB: db,</span><br><span class="line"> ConnPool: db.ConnPool,</span><br><span class="line"> Context: context.Background(),</span><br><span class="line"> Clauses: <span class="keyword">map</span>[<span class="keyword">string</span>]clause.Clause&#123;&#125;,</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 连接时,自动会进行ping操作</span></span><br><span class="line"> <span class="keyword">if</span> err == <span class="literal">nil</span> &amp;&amp; !config.DisableAutomaticPing &#123;</span><br><span class="line"> <span class="keyword">if</span> pinger, ok := db.ConnPool.(<span class="keyword">interface</span>&#123; Ping() error &#125;); ok &#123;</span><br><span class="line"> err = pinger.Ping()</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line"> config.Logger.Error(context.Background(), <span class="string">&quot;failed to initialize database, got error %v&quot;</span>, err)</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure> diff --git a/css/main.css b/css/main.css index ef5fdd87..881ac03b 100644 --- a/css/main.css +++ b/css/main.css @@ -1172,7 +1172,7 @@ pre .javascript .function { } .links-of-author a::before, .links-of-author span.exturl::before { - background: #4e0e5d; + background: #0ab9ff; border-radius: 50%; content: ' '; display: inline-block; diff --git a/page/2/index.html b/page/2/index.html index 78d75541..d12f673e 100644 --- a/page/2/index.html +++ b/page/2/index.html @@ -522,7 +522,7 @@

    更新于 - + @@ -550,7 +550,7 @@

    -

    GORM源码浅析

    连接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    // gorm 连接数据库
    func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
    // 全局配置
    config := &Config{}

    ...

    // 加载配置
    for _, opt := range opts {
    if opt != nil {
    if applyErr := opt.Apply(config); applyErr != nil {
    return nil, applyErr
    }
    defer func(opt Option) {
    if errr := opt.AfterInitialize(db); errr != nil {
    err = errr
    }
    }(opt)
    }
    }

    // 时间精度配置 默认毫秒
    if d, ok := dialector.(interface{ Apply(*Config) error }); ok {
    if err = d.Apply(config); err != nil {
    return
    }
    }


    // 注册query/create..等操作执行时所需要调用的函数
    // gorm:query -> gorm:preload -> gorm:after_query
    // 对不同版本的数据库做相应的约束配置
    // 调用sql.Open()初始化连接池
    db.callbacks = initializeCallbacks(db)
    if config.Dialector != nil {
    err = config.Dialector.Initialize(db)
    }

    ...

    // clone=1
    db = &DB{Config: config, clone: 1}

    // 在执行sql前后,相关的信息都会存在其中
    db.Statement = &Statement{
    DB: db,
    ConnPool: db.ConnPool,
    Context: context.Background(),
    Clauses: map[string]clause.Clause{},
    }

    // 连接时,自动会进行ping操作
    if err == nil && !config.DisableAutomaticPing {
    if pinger, ok := db.ConnPool.(interface{ Ping() error }); ok {
    err = pinger.Ping()
    }
    }

    if err != nil {
    config.Logger.Error(context.Background(), "failed to initialize database, got error %v", err)
    }

    return
    }

    +

    GORM 源码浅析

    连接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    // gorm 连接数据库
    func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
    // 全局配置
    config := &Config{}

    ...

    // 加载配置
    for _, opt := range opts {
    if opt != nil {
    if applyErr := opt.Apply(config); applyErr != nil {
    return nil, applyErr
    }
    defer func(opt Option) {
    if errr := opt.AfterInitialize(db); errr != nil {
    err = errr
    }
    }(opt)
    }
    }

    // 时间精度配置 默认毫秒
    if d, ok := dialector.(interface{ Apply(*Config) error }); ok {
    if err = d.Apply(config); err != nil {
    return
    }
    }


    // 注册query/create..等操作执行时所需要调用的函数
    // gorm:query -> gorm:preload -> gorm:after_query
    // 对不同版本的数据库做相应的约束配置
    // 调用sql.Open()初始化连接池
    db.callbacks = initializeCallbacks(db)
    if config.Dialector != nil {
    err = config.Dialector.Initialize(db)
    }

    ...

    // clone=1
    db = &DB{Config: config, clone: 1}

    // 在执行sql前后,相关的信息都会存在其中
    db.Statement = &Statement{
    DB: db,
    ConnPool: db.ConnPool,
    Context: context.Background(),
    Clauses: map[string]clause.Clause{},
    }

    // 连接时,自动会进行ping操作
    if err == nil && !config.DisableAutomaticPing {
    if pinger, ok := db.ConnPool.(interface{ Ping() error }); ok {
    err = pinger.Ping()
    }
    }

    if err != nil {
    config.Logger.Error(context.Background(), "failed to initialize database, got error %v", err)
    }

    return
    }

    diff --git a/sitemap.xml b/sitemap.xml index 349a9750..98254178 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -303,14 +303,14 @@ - https://cwww3.github.io/2021/05/08/mysql-order-by/ + https://cwww3.github.io/2021/04/24/mysql-log/ 2021-05-26 - https://cwww3.github.io/2021/04/24/mysql-log/ + https://cwww3.github.io/2021/05/08/mysql-order-by/ 2021-05-26 @@ -361,119 +361,119 @@ - https://cwww3.github.io/tags/go/ + https://cwww3.github.io/tags/%E5%AF%86%E7%A0%81%E5%AD%A6/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/GC/ + https://cwww3.github.io/tags/go/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/%E5%AF%86%E7%A0%81%E5%AD%A6/ + https://cwww3.github.io/tags/GC/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/%E7%BD%91%E7%BB%9C/ + https://cwww3.github.io/tags/Go-Question/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/Go-Question/ + https://cwww3.github.io/tags/%E7%AE%97%E6%B3%95/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/IO/ + https://cwww3.github.io/tags/go-%E6%BA%90%E7%A0%81/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/go-%E6%BA%90%E7%A0%81/ + https://cwww3.github.io/tags/Nginx/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/Nginx/ + https://cwww3.github.io/tags/%E7%BC%96%E7%A0%81/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/%E7%AE%97%E6%B3%95/ + https://cwww3.github.io/tags/Docker/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/%E7%BC%96%E7%A0%81/ + https://cwww3.github.io/tags/IO/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/Docker/ + https://cwww3.github.io/tags/%E7%BD%91%E7%BB%9C/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/go-sql/ + https://cwww3.github.io/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/ + https://cwww3.github.io/tags/Gorm/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/memory/ + https://cwww3.github.io/tags/MySql/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/Gorm/ + https://cwww3.github.io/tags/k8s/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/MySql/ + https://cwww3.github.io/tags/memory/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/k8s/ + https://cwww3.github.io/tags/go-sql/ 2024-07-04 daily 0.6 @@ -494,7 +494,7 @@ - https://cwww3.github.io/tags/MongoDB/ + https://cwww3.github.io/tags/os/ 2024-07-04 daily 0.6 @@ -508,7 +508,7 @@ - https://cwww3.github.io/tags/os/ + https://cwww3.github.io/tags/MongoDB/ 2024-07-04 daily 0.6 @@ -522,14 +522,14 @@ - https://cwww3.github.io/tags/%E6%8E%88%E6%9D%83%E8%AE%A4%E8%AF%81/ + https://cwww3.github.io/tags/pprof/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/pprof/ + https://cwww3.github.io/tags/%E6%8E%88%E6%9D%83%E8%AE%A4%E8%AF%81/ 2024-07-04 daily 0.6 @@ -557,28 +557,28 @@ - https://cwww3.github.io/tags/System-Design/ + https://cwww3.github.io/tags/Vim/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/CDN/ + https://cwww3.github.io/tags/System-Design/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/DNS/ + https://cwww3.github.io/tags/CDN/ 2024-07-04 daily 0.6 - https://cwww3.github.io/tags/Vim/ + https://cwww3.github.io/tags/DNS/ 2024-07-04 daily 0.6