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