如何在多个软件包之间共享单个数据库连接



我有两个命名client和worker的软件包。我想与两个软件包共享相同的SSDB,MySQL和Redis连接。我面临的另一个类似的问题在这两个软件包之间共享auth。

app
  -> client pkg
  -> worker pkg
  main.go (contains auth as global variable)

任何人都可以建议我实施这两件事的最佳方法吗?

这是一种对新的GO开发人员而言并不总是很明显的方法,这是一点点肘油脂,但并非可怕复杂的,通常在初学者应用中正常工作:

app
    client // imports storage
    worker // imports storage
    config // all environment-related config goes here
    storage   // storage-engine-generic interface to the packages below it
        ssdb  // all ssdb-specific code here
        mysql // all mysql-specific code here
        redis // ditto

它使用软件包变量。如果您对意外写入到导出的软件包变量的偏执狂,则可以通过使用未备件的软件包变量来避免问题。利用GO中导出标识符的定义有限(请参阅语言规格(。

main中,致电

config.Init(configfile)
storage.Init()

定义您的config.Init函数以读取配置文件并将软件包变量设置为您的连接信息数据库。如果您使用的是ENEXPORT的软件包变量,请允许通过导出的功能通过公开阅读的访问。否则,您可能会跳过功能,具体取决于您想要的其他功能。

storage中,您的Init功能调用

ssdb.Init()
mysql.Init()
redis.Init()

然后在storage中,您将拥有clientserver使用的公共功能,而不是存储引擎,例如

func GetImage(id string) ([]byte) {
    return mysql.GetImage(id)
}

或适合您申请的任何内容。storage抽象级别可能对您来说可能是或不值得的,具体取决于您将来如何更改应用程序。您决定是否值得投资。

mysql软件包中,您导入config,并且有类似

的东西
var db *sql.DB
func Init() {
    getDb()
}
func getDb() (*sql.DB) {
    if db == nil {  // or something
        config.Log.Println("Opening db connection to mysql")
        db, err := sql.Open("mysql", config.MysqlConnectionString())
        // do something with err, possibly have a retry loop
    }
    return db
}
func GetImage(id string) ([]byte)
     db := getDb()
     // ...

MySQL软件包中的函数可以使用db未出现的软件包变量,但其他软件包不能。

使用未出现的软件包变量与导出功能仅读取访问并不是一个糟糕的做法,也不是特别复杂。也就是说,这通常是不必要的。如果db是导出的软件包变量Db,您是否会突然键入

mysql.Db, _ = sql.Open("mysql", "LEEERRROOYYYYY!!!!")

在您的client代码中(还决定导入mysqlsql进行操作(然后部署到生产中?为什么您会比故意打破代码的其他任何部分更有可能这样做?

请注意,如果您刚输入

mysql.Db = "LEEERRROOYYYYYY!!!!"

您的应用程序由于类型不匹配而无法编译。

有很多方法可以做到这一点,每种方法都有优点和缺点,这实际上取决于您在做什么。一种简单的方法是将第三个包装带有数据库连接,然后从其他两个软件包和主包装中导入它。

app
  -> client pkg // import "app/global"
  -> worker pkg // import "app/global"
  -> global pkg // Contains ssdb and auth as global variables
  main.go

另一种可能取决于您正在做的事情可能更好的方法是在clientworker软件包上将功能接受DB连接作为参数,并且main.go在调用函数时将DB初始化并将其传递给参数需要它。

这取决于您在做什么,但是对于大型项目而言,如果您只有一个包裹可以执行所有数据库操作,并且可以从所有需要做某事的地方访问它,那么维护就更容易维护。这样,您就不必担心这个问题,因为即使有多个软件包使用它,也只需要担心数据库连接。

编辑:

全局变量的问题在于,它们可以同时从项目中的任何地方进行修改,并且可以引入种族条件,但是在这不是问题时使用它们没有错。

在这种情况下,您只是设置一个值一次,当您连接到DB,然后使用对象。

您提到您想为Auth拥有另一个软件包,我建议您只拥有一个软件包,并拥有您需要从一个以上的软件包访问的所有内容,在这种情况下为SSDB和AUTH。

最新更新