db_conn.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package dao
  2. import (
  3. _ "github.com/go-sql-driver/mysql"
  4. "github.com/spf13/viper"
  5. "os"
  6. "os/signal"
  7. "strings"
  8. "sync"
  9. "time"
  10. "xorm.io/xorm"
  11. )
  12. var (
  13. dbConnMap = make(map[string]*DBInfo)
  14. dbOnce sync.Once
  15. )
  16. type DBInfo struct {
  17. Name string
  18. DB *xorm.Engine
  19. }
  20. func init() {
  21. viper.SetDefault("db.global.max_idle", 4000)
  22. viper.SetDefault("db.global.max_open", 8000)
  23. viper.SetDefault("db.global.max_lifetime", 8000000000)
  24. viper.SetDefault("db.spider.host", "root:123456@tcp(localhost:3306)")
  25. viper.SetDefault("db.spider.name", "spider")
  26. }
  27. // 获取特定数据库访问对象的实例
  28. func DB(name string) *xorm.Engine {
  29. if len(strings.TrimSpace(name)) == 0 {
  30. return nil
  31. }
  32. openDB()
  33. if info, ok := dbConnMap[name]; ok {
  34. return info.DB
  35. } else {
  36. println("DB "+name+" disconnected")
  37. return nil
  38. }
  39. }
  40. // 打开所有数据库
  41. func openDB() {
  42. dbOnce.Do(func() { // 一次程序运行仅执行一次,以达到“单例”的效果
  43. readDBConfigAndOpen()
  44. go func() {
  45. defer closeDB()
  46. quit := make(chan os.Signal)
  47. signal.Notify(quit, os.Interrupt)
  48. <-quit
  49. }()
  50. })
  51. }
  52. // 关闭所有数据库
  53. func closeDB() {
  54. if nil == dbConnMap || len(dbConnMap) == 0 {
  55. return
  56. }
  57. for _, dbInfo := range dbConnMap {
  58. if nil != dbInfo && nil != dbInfo.DB {
  59. err := dbInfo.DB.Close()
  60. if nil != err {
  61. println("Close db "+dbInfo.Name+" failed:", err.Error())
  62. continue
  63. }
  64. println("Close db " + dbInfo.Name)
  65. }
  66. }
  67. }
  68. // 读取配置文件并进行数据库连接,方法名首字母小写即为包私有方法,否则若大写则为公共方法
  69. func readDBConfigAndOpen() {
  70. dbs := viper.GetStringMap("db")
  71. if nil == dbs || len(dbs) == 0 {
  72. println("not found any DB config")
  73. return
  74. }
  75. globalMaxIdle := viper.GetInt("db.global.max_idle")
  76. globalMaxOpen := viper.GetInt("db.global.max_open")
  77. globalMaxLifetime := viper.GetDuration("db.global.max_lifetime")
  78. for name := range dbs {
  79. key := name
  80. if key == "global" {
  81. continue
  82. }
  83. cnf := dbs[key].(map[string]interface{})
  84. if nil == cnf {
  85. println("wrong DB config")
  86. return
  87. }
  88. var dbHost, dbName, maxIdle, maxOpen, maxLifetime interface{}
  89. var ok bool
  90. if dbHost, ok = cnf["host"]; !ok {
  91. println("wrong DB host config")
  92. return
  93. }
  94. if dbName, ok = cnf["name"]; !ok {
  95. println("wrong DB name config")
  96. return
  97. }
  98. if maxIdle, ok = cnf["max_idle"]; !ok {
  99. maxIdle = globalMaxIdle
  100. }
  101. if maxOpen, ok = cnf["max_open"]; !ok {
  102. maxOpen = globalMaxOpen
  103. }
  104. if maxLifetime, ok = cnf["max_lifetime"]; !ok {
  105. maxLifetime = globalMaxLifetime
  106. }
  107. newDB(name, dbHost.(string), dbName.(string),
  108. maxIdle.(int), maxOpen.(int), maxLifetime.(time.Duration))
  109. }
  110. }
  111. func newDB(name string, dbHost string, dbName string,
  112. maxIdle int, maxOpen int, maxLifetime time.Duration) {
  113. db, err := xorm.NewEngine("mysql", dbHost+"/"+dbName+"?charset=utf8&parseTime=True&loc=Local")
  114. if err != nil {
  115. println("Open DB conn failed", err.Error())
  116. return
  117. }
  118. // 设置连接池的空闲数大小
  119. if maxIdle > 0 {
  120. db.SetMaxIdleConns(maxIdle)
  121. }
  122. // 设置最大打开连接数
  123. if maxOpen > 0 {
  124. db.SetMaxOpenConns(maxOpen)
  125. }
  126. // 设置最大连接超时时间
  127. if maxLifetime > 0 {
  128. db.SetConnMaxLifetime(maxLifetime)
  129. }
  130. // 连接测试
  131. if err = db.DB().Ping(); err != nil {
  132. println("Can not conn to DB", err.Error())
  133. return
  134. }
  135. println("Open db " + dbName)
  136. dbConnMap[name] = &DBInfo{Name: dbName, DB: db}
  137. }