我正在开发一个包含多个数据库的Go RESTful API应用程序。启动服务器时,用户会提供他们想要使用的数据库。
在应用程序中,我有三个函数,其中一个处理连接:selectedDb.Get()
,selectedDb.Add()
,selectedDb.Connect()
。
如果有人选择Mysql,它会为Mysql处理事情,如果有人选择了MongoDB,它会为Mongo处理事情,等等。
这是尝试完成此任务的方式:
DbInterface.go
package dbinit
type Object struct {
Uuid string
Object string
Deleted bool
}
// The interface that all connectors should have
type Intfc interface {
Connect() HERE_LIES_MY_PROBLEM
Add(string, string, string) string
Get(string) (Object, bool)
}
MySQL.go
package mysqlConnector
import (
...
)
type Mysql struct{}
// Connect to mysql
func (f Mysql) Connect() HERE_LIES_MY_PROBLEM {
client, err = sql.Open("mysql", "yourusername:yourpassword@/yourdatabase")
if err != nil {
panic(err.Error())
}
return client
}
// Add item to DB
func (f Mysql) Add(owner string, refType string, object string) string {
// do stuff related to this DB
return // a string
}
func (f Mysql) Get(Uuid string) (dbinit.Object, bool) {
// do stuff related to this DB
return // an object and a bool
}
Mongo.go
package mongoConnector
import (
...
)
type Mongo struct{}
// Connect to mongo
func (f Mongo) Connect() HERE_LIES_MY_PROBLEM {
info := &mgo.DialInfo{
Addrs: []string{hosts},
Timeout: 60 * time.Second,
Database: database,
Username: username,
Password: password,
}
client, err := mgo.DialWithInfo(info)
if err != nil {
panic(err)
}
return client
}
// Add item to DB
func (f Mongo) Add(owner string, refType string, object string) string {
// do stuff related to this DB
return // a string
}
func (f Mongo) Get(Uuid string) (dbinit.Object, bool) {
// do stuff related to this DB
return // an object and a bool
}
main.go
...
var selectedDb dbinit.Intfc
commandLineInput := "mysql" // just for the example
if commandLineInput == "mysql" {
selectedDb = mysqlConnector.Mysql{}
} else if commandLineInput == "mongo" {
selectedDb = mongoConnector.Mongo{}
}
client := selectedDb.Connect()
// this runs everytime the API is called
api.HandlerFoobar = foobar.handlerFunction(func(params foobar.Params) middleware.Responder {
// Here I want to add something to the selected dbinit
selectedDb.Get(client, addStringA, addStringB, addStringC)
return // the API response
})
...
问题陈述
当我返回Mysql的客户端时,它不适用于Mongo,反之亦然。
我想在启动服务器时将数据库连接到数据库并将client
存储在客户端变量中。然而,问题是Mongo返回的另一个客户端而不是Mysql等等。
HERE_LIES_MY_PROBLEM
的位置应该是什么?答案 0 :(得分:1)
阐述我的评论,而不是
type Intfc interface {
Connect() HERE_LIES_MY_PROBLEM
Add(string, string, string) string
Get(string) (Object, bool)
}
你可以使用
type Intfc interface {
Connect() DBClient
}
和
type DBClient interface {
Add(string, string, string) string
Get(string) (Object, bool)
}
type MySQLClient sql.DB
type MongoClient mgo.Session
func (f Mysql) Connect() DBCLient {
client, err = sql.Open("mysql", "yourusername:yourpassword@/yourdatabase")
if err != nil {
panic(err.Error())
}
return MySQLClient(client)
}
func (f Mongo) Connect() DBClient {
info := &mgo.DialInfo{
Addrs: []string{hosts},
Timeout: 60 * time.Second,
Database: database,
Username: username,
Password: password,
}
client, err := mgo.DialWithInfo(info)
if err != nil {
panic(err)
}
return MongoClient(client)
}
func (s *MySQLClient) Add(...) {
// ...
}
func (s *MongoClient) Add(...) {
// ...
}
答案 1 :(得分:1)
我认为,界面Intfc(或更好的名称DbIntfc)应该只有Get和Add方法。
它应该存在另一个函数 - 但不是DbIntfc的一部分,返回DbIntfc - 连接到MySql或MongoDb。让我们来看看:
type MySqlDbIntfc struct{
db *Sql.DB
}
// Connect to mysql
func NewMySqlDbIntfc() (DbIntfc,error) {
// Please do not prefer panic in such abstract methods
client, err := sql.Open("mysql", "yourusername:yourpassword@/yourdatabase")
if err != nil {
return nil, err
}
return &MySqlDbIntfc{client}, nil
}
func (mySqlDb *MySqlDbIntfc) Get(Uuid string) (dbinit.Object, error) {
var obj dbinit.Object
err := mySqlDb.db.QueryRow("SELECT uuid, object, deleted FROM myTable WHERE uuid=?", Uuid).Scan(&obj.Uuid, &obj.Object, &obj.Deleted)
if err != nil {
return dbinit.Object{}, err
}
return obj, nil
}
实现NewMgoDbIntfc应该很简单,包括方法NewMgoDbIntfc.Add / Get。
决定是否使用NewMySqlDbIntfc或NewMgoDbIntfc也应该很容易。
答案 2 :(得分:0)
- 我在代码中有HERE_LIES_MY_PROBLEM的地方应该包含哪些内容?
醇>
正如您从the source可以看到DialWithInfo()
返回error
和*Session
来自mgo
包,这是struct
。因此,您可以将{strong> HERE_LIES_MY_PROBLEM 替换为*mgo.Session
- 在处理这些事情时,我的Go范例是否错误?
醇>
至于连接多个数据库的惯用语,我认为有很多意见。以下是我与mongo和redis联系的一些想法:
var logger *log.Logger
func init() {
logger = log.New(os.Stderr,
"Database :: ",
log.Ldate|log.Ltime|log.Lshortfile)
}
//we create different types of databse connection here.
func SystemConnection() map[string]interface{} {
listConnection := make(map[string]interface{})
var err error
// create redis connection
redisConn := RedisHost{
Address: "localhost:6379",
Password: "",
DB: 0,
}
redisConnection, err := redisConn.Connect()
if err != nil {
panic(err)
}
//create mongodb connection
mongo := MongoHost{
Host: "localhost",
Port: "27017",
}
mongoConnection := mongo.Connect()
listConnection["redis"] = redisConnection
listConnection["mongodb"] = mongoConnection
return listConnection
}
func GetMongo() *mgo.Session {
//create mongodb connection
mongo := MongoHost{
Host: "localhost",
Port: "27017",
}
mongoConnection := mongo.Connect()
return mongoConnection
}
您可以看到来源from here
要使用上述代码,您可以在主程序中调用SystemConnection()
上的init()
。像这样:
func init(){
listConnection := database.SystemConnection()
//getting redis connection convert it from interface to *redisClient.
redisConn := listConnection["redis"].(*redis.Client)
// get postgre connection.
mongoConn := listConnection["mongodb"].(*mgo.Session)
}
我认为这种方法可能适用于你的其他方法。