component.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package mhayaGORM
  2. import (
  3. "fmt"
  4. "time"
  5. cfacade "github.com/mhaya/facade"
  6. clog "github.com/mhaya/logger"
  7. cprofile "github.com/mhaya/profile"
  8. "gorm.io/driver/clickhouse"
  9. "gorm.io/driver/mysql"
  10. "gorm.io/gorm"
  11. "gorm.io/gorm/logger"
  12. )
  13. const (
  14. Name = "gorm_component"
  15. MysqlDBType = "mysql"
  16. ClickhouseDBType = "clickhouse"
  17. mysqlDsn = "%s:%s@(%s)/%s?charset=utf8&parseTime=True&loc=Local"
  18. clickhouseDsn = "clickhouse://%s:%s@%s/%s?dial_timeout=10s&read_timeout=20s"
  19. )
  20. type (
  21. Component struct {
  22. cfacade.Component
  23. // key:groupId,value:{key:id,value:*gorm.Db}
  24. ormMap map[string]map[string]*gorm.DB
  25. }
  26. dbConfig struct {
  27. Enable bool
  28. GroupId string
  29. Id string
  30. DbName string
  31. Host string
  32. UserName string
  33. Password string
  34. MaxIdleConnect int
  35. MaxOpenConnect int
  36. LogMode bool
  37. DSN string
  38. DBType string
  39. }
  40. // HashDb hash by group id
  41. HashDb func(dbMaps map[string]*gorm.DB) string
  42. )
  43. func NewComponent() *Component {
  44. return &Component{
  45. ormMap: make(map[string]map[string]*gorm.DB),
  46. }
  47. }
  48. func (s *Component) Name() string {
  49. return Name
  50. }
  51. func parseDbConfig(groupId string, item cfacade.ProfileJSON) *dbConfig {
  52. return &dbConfig{
  53. GroupId: groupId,
  54. Id: item.GetString("db_id"),
  55. DBType: item.GetString("db_type", ""),
  56. DSN: item.GetString("dsn", ""),
  57. DbName: item.GetString("db_name"),
  58. Host: item.GetString("host"),
  59. UserName: item.GetString("user_name"),
  60. Password: item.GetString("password"),
  61. MaxIdleConnect: item.GetInt("max_idle_connect", 4),
  62. MaxOpenConnect: item.GetInt("max_open_connect", 8),
  63. LogMode: item.GetBool("log_mode", true),
  64. Enable: item.GetBool("enable", true),
  65. }
  66. }
  67. func (s *Component) Init() {
  68. // load only the database contained in the `db_id_list`
  69. dbIdList := s.App().Settings().Get("db_id_list")
  70. if dbIdList.LastError() != nil || dbIdList.Size() < 1 {
  71. clog.Warnf("[nodeId = %s] `db_id_list` property not exists.", s.App().NodeId())
  72. return
  73. }
  74. dbConfig := cprofile.GetConfig("db")
  75. if dbConfig.LastError() != nil {
  76. clog.Panic("`db` property not exists in profile file.")
  77. }
  78. for _, groupId := range dbConfig.Keys() {
  79. s.ormMap[groupId] = make(map[string]*gorm.DB)
  80. dbGroup := dbConfig.GetConfig(groupId)
  81. for i := 0; i < dbGroup.Size(); i++ {
  82. item := dbGroup.GetConfig(i)
  83. config := parseDbConfig(groupId, item)
  84. for _, key := range dbIdList.Keys() {
  85. if dbIdList.Get(key).ToString() != config.Id {
  86. continue
  87. }
  88. if !config.Enable {
  89. clog.Panicf("[dbName = %s] is disabled!", config.DbName)
  90. }
  91. switch config.DBType {
  92. case MysqlDBType:
  93. db, err := s.createORM(config)
  94. if err != nil {
  95. clog.Panicf("[dbName = %s] create orm fail. error = %s", config.DbName, err)
  96. }
  97. s.ormMap[groupId][config.Id] = db
  98. case ClickhouseDBType:
  99. db, err := s.createClickHouseORM(config)
  100. if err != nil {
  101. clog.Panicf("[dbName = %s] create chickorm fail. error = %s", config.DbName, err)
  102. }
  103. s.ormMap[groupId][config.Id] = db
  104. default:
  105. clog.Panicf("unknow dbName = %s", config.DbName)
  106. }
  107. clog.Infof("[dbGroup =%s, dbName = %s] is connected.", config.GroupId, config.Id)
  108. }
  109. }
  110. }
  111. }
  112. func (s *Component) createORM(cfg *dbConfig) (*gorm.DB, error) {
  113. db, err := gorm.Open(mysql.Open(cfg.GetDSN()), &gorm.Config{
  114. Logger: getLogger(),
  115. })
  116. if err != nil {
  117. return nil, err
  118. }
  119. sqlDB, err := db.DB()
  120. if err != nil {
  121. return nil, err
  122. }
  123. sqlDB.SetMaxIdleConns(cfg.MaxIdleConnect)
  124. sqlDB.SetMaxOpenConns(cfg.MaxOpenConnect)
  125. sqlDB.SetConnMaxLifetime(time.Minute)
  126. if cfg.LogMode {
  127. return db.Debug(), nil
  128. }
  129. return db, nil
  130. }
  131. func getLogger() logger.Interface {
  132. return logger.New(
  133. gormLogger{log: clog.DefaultLogger},
  134. logger.Config{
  135. SlowThreshold: time.Second,
  136. LogLevel: logger.Silent,
  137. Colorful: true,
  138. },
  139. )
  140. }
  141. func (s *Component) GetDb(id string) *gorm.DB {
  142. for _, group := range s.ormMap {
  143. for k, v := range group {
  144. if k == id {
  145. return v
  146. }
  147. }
  148. }
  149. return nil
  150. }
  151. func (s *Component) GetHashDb(groupId string, hashFn HashDb) (*gorm.DB, bool) {
  152. dbGroup, found := s.GetDbMap(groupId)
  153. if !found {
  154. clog.Warnf("groupId = %s not found.", groupId)
  155. return nil, false
  156. }
  157. dbId := hashFn(dbGroup)
  158. db, found := dbGroup[dbId]
  159. return db, found
  160. }
  161. func (s *Component) GetDbMap(groupId string) (map[string]*gorm.DB, bool) {
  162. dbGroup, found := s.ormMap[groupId]
  163. return dbGroup, found
  164. }
  165. func (s *dbConfig) GetDSN() string {
  166. if s.DSN != "" {
  167. return s.DSN
  168. }
  169. switch s.DBType {
  170. case MysqlDBType:
  171. s.DSN = mysqlDsn
  172. return fmt.Sprintf(s.DSN, s.UserName, s.Password, s.Host, s.DbName)
  173. case ClickhouseDBType:
  174. s.DSN = clickhouseDsn
  175. return fmt.Sprintf(s.DSN, s.UserName, s.Password, s.Host, s.DbName)
  176. default:
  177. // never reach
  178. return ""
  179. }
  180. }
  181. func (s *Component) createClickHouseORM(cfg *dbConfig) (*gorm.DB, error) {
  182. db, err := gorm.Open(clickhouse.Open(cfg.GetDSN()), &gorm.Config{
  183. Logger: getLogger(),
  184. })
  185. if err != nil {
  186. return nil, err
  187. }
  188. sqlDB, err := db.DB()
  189. if err != nil {
  190. return nil, err
  191. }
  192. sqlDB.SetConnMaxLifetime(time.Minute)
  193. if cfg.LogMode {
  194. return db.Debug(), nil
  195. }
  196. return db, nil
  197. }