Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 架构交换支持GORM_Sql_Postgresql_Go_Orm - Fatal编程技术网

Sql 架构交换支持GORM

Sql 架构交换支持GORM,sql,postgresql,go,orm,Sql,Postgresql,Go,Orm,我正在编写一个RESTAPI,在其中我需要动态地将连接部署到多个模式 示例:我有两个模式,其中我需要根据尝试使用数据的用户进行更改 这个想法是要有许多其他的方案,每个用户一个 我看到了这个问题,但使用的示例需要找到一种动态更改的方法。我将把用户模式放在JWT令牌中 我的项目: 有什么建议吗?选项1 您可以更改database.GetConnection()方法以接收用户名并直接连接到数据库,而无需更改所有服务和模型。您将用户存储在security\u middleware.go上的gin.Con

我正在编写一个RESTAPI,在其中我需要动态地将连接部署到多个模式

示例:我有两个模式,其中我需要根据尝试使用数据的用户进行更改

这个想法是要有许多其他的方案,每个用户一个

我看到了这个问题,但使用的示例需要找到一种动态更改的方法。我将把用户模式放在JWT令牌中

我的项目:

有什么建议吗?

选项1 您可以更改database.GetConnection()方法以接收用户名并直接连接到数据库,而无需更改所有服务和模型。您将用户存储在
security\u middleware.go
上的gin.Context对象中,这样您就可以在控制器上从那里获取用户并将其传递给服务,以便它们获得相应的DB连接

但为此,您必须删除单例模式您必须存储DB对象并创建一个DB对象池,可能在
map[string]*DB
中,而不是在服务包中缓存DB对象,而是在数据库包中缓存所有用户DB对象

您的
数据库/database.go
文件将类似于:

// Add sync import to handle concurrent access to the cache
import "sync"

// ... existent code

// DB objects cache
type DBs struct {
    Cache map[string]*gorm.DB
    sync.RWMutex
}

var dbs *DBs

// Init cache
func init() {
    dbs = DBs{
        Cache: make(map[string]*gorm.DB)
    }
}

func GetConnection(username string) *gorm.DB {  
    // Try to get connection from the cache
    dbs.RLock()
    if db, ok := dbs.Cache[username]; ok {
        dbs.RUnlock()
        return db
    }

    // Figure out DB_NAME dynamically here, based on username...
    //...
    dbName := figuredOutDB_NAME    

    db, err := gorm.Open(DB_DATABASE, "host=" + DB_HOST + " user=" + DB_USER + " dbname=" + dbName + " sslmode=" + DB_SSL_MODE + " password=" + DB_PASSWORD)

    if err != nil {
        panic(err)
    }

    //Ativa log de todas as saidas da conexão (SQL)
    db.LogMode(GetENVLogMode())
    //Seta o maximo de conexões
    db.DB().SetMaxIdleConns(DB_MAX_CONNECTION)
    db.DB().SetMaxOpenConns(DB_MAX_CONNECTION)

    DropTablesIfExists(db)
    AutoMigrate(db)
    AutoPopulate(db)
    AddForeignKeys(db)

    // Save connection to cache
    dbs.Lock()
    dbs.Cache[username] = db
    dbs.Unlock()

    return db
}

// ... and so on
然后删除
services/services.go
文件,因为它没有用处。 并更改服务方法以将用户名作为参数接收,而不是使用
Con
变量,每次调用
Con:=database.GetConnection(username)

我希望这能给你一个可能的解决办法。当然,可能还有其他选择,但这正是我现在能想到的

我看到的这个方法的问题是,系统中的每个用户都有一个打开的连接(和一个gorm.DB对象),不确定预期的用户数,但这可能是个问题

选择2 另一种解决方案是在服务上遵循相同的更改,以便它们在所有方法上以参数形式接收用户,但不是获得新连接,而是将username/db name设置为自定义模型属性,您可以使用该属性实现自己的
model.TableName()
方法,该方法使用该属性返回
schema.table
格式

因此,您可以将模型更改为具有setter的私有属性,如:

type Person struct {
   schemaName string

   // ... existent properties.
}

func (p *Person) SetUser(u string) string {
    // Figure out the schema name from the username
    //...

    p.schemaName = schema
}

func (p *Person) TableName() string {
    return p.schemaName + ".persons"
}
然后,在您的服务上,您可以在每次创建新模型实例时设置用户:

func GetPeople(pag helpers.Pagination, q url.Values, username string) models.People {

    var people models.People
    (&people).SetUser(username)

    db := Con

    // ... and so on

这是我现在可以考虑的两个可能的解决方案。可能会有更多更好的,但希望能有所帮助

您的建议非常好,但我最终忘记了使用POSTGRESQL,其目的不是更改数据库,而是更改模式。这是有道理的,我习惯于使用MySQL,其中模式和数据库是相同的。在这种情况下,选项2应该适合您。