在Golang:如何处理未知变量或如何处理多个数据库?

时间:2017-05-03 09:17:32

标签: go

我正在开发一个包含多个数据库的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等等。

  1. 我在代码中HERE_LIES_MY_PROBLEM的位置应该是什么?
  2. 或者我是否因为处理这些事情而错误地使用Go范例?

3 个答案:

答案 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)

  
      
  1. 我在代码中有HERE_LIES_MY_PROBLEM的地方应该包含哪些内容?
  2.   

正如您从the source可以看到DialWithInfo()返回error*Session来自mgo包,这是struct。因此,您可以将{strong> HERE_LIES_MY_PROBLEM 替换为*mgo.Session

  
      
  1. 在处理这些事情时,我的Go范例是否错误?
  2.   

至于连接多个数据库的惯用语,我认为有很多意见。以下是我与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)

}

我认为这种方法可能适用于你的其他方法。