gogf / gf

GoFrame is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
https://goframe.org
MIT License
11.76k stars 1.6k forks source link

database/gdb: In the transaction, the Schema method does not take effect and the corresponding table structure cannot be obtained correctly. #3876

Open yimuysl001 opened 1 month ago

yimuysl001 commented 1 month ago

Go version

go1.20.14 windows/amd64

GoFrame version

2.7.4

Can this bug be reproduced with the latest release?

Option Yes

What did you do?

复现bug代码:

1.表结构

use BAK -- 分别在一个数据源当中的不同数据库中创建表格
create table TBA(
    id int,
    name varchar(10),
) 
use ELT -- 分别在一个数据源当中的不同数据库中创建表格
create table TBB(
    id int,
    name varchar(10),
) 

2.使用tx事务问题

func main() {
    err := g.DB("local").Transaction(gctx.New(), func(ctx context.Context, tx gdb.TX) error {
        // local 配置使用连接用的其他库
        // 使用 Schema 未能正常切换到相应的库当中
        _, err := tx.Model("TBA").Schema("BAK").Insert(map[string]interface{}{
            "id":   1,
            "name": "aaa",
        })
        if err != nil {
            return err
        }

        _, err = tx.Model("TBB").Schema("ELT").Insert(map[string]interface{}{
            "id":   1,
            "name": "aaa",
        })
        return err
    })

    fmt.Println(err) // 报错 The table "TBA" may not exist, or the table contains no fields
}    

3.使用ctx 事务


func main() {
    err := g.DB("local").Transaction(gctx.New(), func(ctx context.Context, tx gdb.TX) error {
        // local 配置使用连接用的其他库
        // 使用 Schema 未能正常切换到相应的库当中
        _, err := g.DB("local").Ctx(ctx).Model("TBA").Schema("BAK").Insert(map[string]interface{}{
            "id":   1,
            "name": "aaa",
        })
        if err != nil {
            return err
        }
        _, err = g.DB("local").Ctx(ctx).Model("TBB").Schema("ELT").Insert(map[string]interface{}{
            "id":   1,
            "name": "aaa",
        })
        return err
    })
    fmt.Println(err) // 报错 The table "TBA" may not exist, or the table contains no fields
}
  1. Schema在Model前面

    
    func main() {
    
    err := g.DB("local").Transaction(gctx.New(), func(ctx context.Context, tx gdb.TX) error {
           // 切换了 Model 与 Schema 的位置
        _, err := g.DB("local").Ctx(ctx).Schema("BAK").Model("TBA").Insert(map[string]interface{}{
            "id":   1,
            "name": "aaa",
        })
        if err != nil {
            return err
        }
    
        _, err = g.DB("local").Ctx(ctx).Schema("ELT").Model("TBB").Insert(map[string]interface{}{
            "id":   1,
            "name": "aaa",
        })
        return err
    })
    fmt.Println(err) // 数据保存成功,但是不是在事务中保存的,而是单独新链接保存的数据,事务中间报错无法回滚数据
    }

What did you see happen?

如果数据涉及到分库分表,需要在一个数据源跨库进行数据增删改查的操作,目前使用gdb的事务,一个事务只能在一个库中进行操作,无法有效获取数据源其他库的表结构,无法保存数据

What did you expect to see?

希望能在事务中提供类似Schema的方法,让数据能够正常处理;或者提供一个方法,如果没查到表结构,使用需要提交map的key来做数据的字段(目前是直接报错,无法在model(aaa..bbb)的方式强制切换库)

UncleChair commented 1 month ago

应该不算是bug,之前有看到过 #3820 这个issue的回复

Issues-translate-bot commented 1 month ago

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


It should not be considered a bug. I have seen the [reply] of this issue #3820 before (https://github.com/gogf/gf/issues/3820#issuecomment-2381908710)

yimuysl001 commented 1 month ago

@UncleChair 如果不支持跨库,能直接用.model(tableName) 和data 拼接sql也行呀,现在是如果没查到表字段直接报错,至少是希望如果没查到表字段,直接使用data里面的key,表明直接使用 传的tableName.

Issues-translate-bot commented 1 month ago

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


@UncleChair If cross-database support is not supported, you can directly use .model(tableName) and data to splice sql. Now, if the table field is not found, an error will be reported directly. At least I hope that if the table field is not found, you can directly use the data in the data. key, indicating that the passed tableName is used directly.

gqcn commented 4 weeks ago

@UncleChair 如果不支持跨库,能直接用.model(tableName) 和data 拼接sql也行呀,现在是如果没查到表字段直接报错,至少是希望如果没查到表字段,直接使用data里面的key,表明直接使用 传的tableName.

@yimuysl001 你好,我理解数据库应该本身不支持跨库的?所以Schema数据库切换实际上是没有保存之前的事务链接的。

Issues-translate-bot commented 4 weeks ago

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


@UncleChair If cross-database support is not supported, you can directly use .model(tableName) and data to splice sql. Now, if a table field is not found, an error will be reported directly. At least I hope that if a table field is not found, it can be directly used in data. The key indicates that the passed tableName is used directly.

@yimuysl001 Hello, I understand that the database itself does not support cross-database? Therefore, Schema database switching does not actually save the previous transaction links.