我正在编写一个REST API,我需要动态地将连接部署到多个模式。
示例:我有两个模式,我需要根据哪个用户尝试使用数据进行更改。
我们的想法是拥有许多其他方案,每个用户一个。
我看到了这个问题,但使用的示例是static,需要找到动态更改的方法。我将用户架构放在JWT令牌中。
我的项目:Panda-API
有什么建议吗?
答案 0 :(得分:0)
您可以更改database.GetConnection()方法以接收用户名并直接连接到数据库,而无需更改所有服务和模型。您将用户存储在security_middleware.go
上的gin.Context对象中,因此您可以从控制器上获取它并将其传递给服务,以便它们获得相应的数据库连接。
但是为此,你必须删除你必须存储DB对象的Singleton模式并创建一个DB对象池,可能在map[string]*DB
中,而不是在服务包中缓存DB对象,缓存数据库包中的所有用户数据库对象。
您的database/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对象),不确定您有多少用户期望,但它可能是个问题。
另一种解决方案是对服务进行相同的更改,以便它们将用户作为所有方法的参数接收,但不是获取新连接,而是将用户名/ db名称设置为可用于的自定义模型属性实现您自己的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
这是我现在可以想到的两种可能的解决方案。可能会有更多更好,但希望有所帮助。