interfaces.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package drivers
  2. import (
  3. "context"
  4. "dbview/service/internal/common/databases/meta"
  5. "fmt"
  6. "math"
  7. "regexp"
  8. "strconv"
  9. "sync"
  10. )
  11. type Connection interface {
  12. Close() error
  13. Ping(context.Context) error
  14. }
  15. // 驱动接口 - 所有数据库驱动必须实现
  16. type Driver interface {
  17. Open(config *meta.ConnectionConfig) (Connection, error)
  18. Version() string
  19. }
  20. // 驱动注册表
  21. type DriverRegistry struct {
  22. drivers map[string]map[string]Driver // 格式: dbType -> version -> Driver
  23. mu sync.RWMutex
  24. }
  25. var globalRegistry = &DriverRegistry{
  26. drivers: make(map[string]map[string]Driver),
  27. }
  28. // RegisterDriver 将指定数据库类型与版本的驱动注册进全局注册表(线程安全)。
  29. // 参数:
  30. // - dbType: 数据库类型标识,如 mysql、postgres。
  31. // - version: 驱动适配的版本号,如 v8、8.0。
  32. // - driver: 实际的驱动实现实例。
  33. //
  34. // 返回值:无;若类型+版本重复注册会直接 panic,提示冲突原因。
  35. func RegisterDriver(dbType, version string, driver Driver) {
  36. globalRegistry.mu.Lock()
  37. defer globalRegistry.mu.Unlock()
  38. if _, ok := globalRegistry.drivers[dbType]; !ok {
  39. globalRegistry.drivers[dbType] = make(map[string]Driver)
  40. }
  41. // 防止重复注册
  42. if _, exists := globalRegistry.drivers[dbType][version]; exists {
  43. panic(fmt.Sprintf("数据库驱动注册冲突:类型 %s 的版本 %s 已存在,请勿重复加载", dbType, version))
  44. }
  45. globalRegistry.drivers[dbType][version] = driver
  46. }
  47. // Connect 根据数据库类型与版本规范创建连接实例。
  48. // 参数:
  49. // - dbType: 数据库类型标识。
  50. // - DbVersion: 版本字符串,可为精确或语义化版本描述。
  51. // - config: 连接配置,包含Host/Port/用户名等信息。
  52. //
  53. // 返回值:
  54. // - Connection: 成功时返回可用于执行数据库操作的连接包装。
  55. // - error: 若无匹配驱动或打开失败则返回相应错误。
  56. func Connect(dbType, DbVersion string, config *meta.ConnectionConfig) (Connection, error) {
  57. driver, err := GetDriver(dbType, DbVersion)
  58. if err != nil {
  59. return nil, err
  60. }
  61. return driver.Open(config)
  62. }
  63. // GetDriver 从注册表中获取指定数据库类型与版本规范的驱动。
  64. // 参数:
  65. // - dbType: 数据库类型标识。
  66. // - versionSpec: 版本规范,支持精确版本与语义化匹配(如 v8、8.0、8)。
  67. //
  68. // 返回值:
  69. // - Driver: 找到时返回对应驱动实例。
  70. // - error: 当类型或版本不存在时返回详细错误提示。
  71. func GetDriver(dbType, versionSpec string) (Driver, error) {
  72. globalRegistry.mu.RLock()
  73. defer globalRegistry.mu.RUnlock()
  74. versions, ok := globalRegistry.drivers[dbType]
  75. if !ok {
  76. return nil, fmt.Errorf("未找到数据库类型 %s 对应的驱动实现,请确认驱动已正确注册", dbType)
  77. }
  78. // 精确匹配
  79. if driver, ok := versions[versionSpec]; ok {
  80. return driver, nil
  81. }
  82. // 模糊化版本匹配:提取数字序列并按首个数字的距离最小化来选择最近的版本。
  83. // 例如:传入 "8.0.27",已注册的 "v8" 或 "8" 会匹配(首个数字均为 8)。
  84. // 优先级:完全数字匹配 -> 最小首位数字差 -> 报错。
  85. extractNums := func(s string) []int {
  86. re := regexp.MustCompile(`\d+`)
  87. parts := re.FindAllString(s, -1)
  88. out := make([]int, 0, len(parts))
  89. for _, p := range parts {
  90. if n, err := strconv.Atoi(p); err == nil {
  91. out = append(out, n)
  92. }
  93. }
  94. return out
  95. }
  96. specNums := extractNums(versionSpec)
  97. if len(specNums) == 0 {
  98. return nil, fmt.Errorf("未找到数据库类型 %s 对应的版本 %s 驱动实现,请确认驱动已正确注册", dbType, versionSpec)
  99. }
  100. var best Driver
  101. bestDiff := math.MaxInt32
  102. found := false
  103. for ver, drv := range versions {
  104. vnums := extractNums(ver)
  105. if len(vnums) == 0 {
  106. continue
  107. }
  108. // 如果任何数字完全匹配(首位或任一位),优先返回
  109. for _, vn := range vnums {
  110. if vn == specNums[0] {
  111. return drv, nil
  112. }
  113. }
  114. // 否则以首位数字差作为距离度量
  115. diff := int(math.Abs(float64(vnums[0] - specNums[0])))
  116. if diff < bestDiff {
  117. bestDiff = diff
  118. best = drv
  119. found = true
  120. }
  121. }
  122. if found {
  123. return best, nil
  124. }
  125. return nil, fmt.Errorf("未找到数据库类型 %s 对应的版本 %s 驱动实现,请确认驱动已正确注册", dbType, versionSpec)
  126. }
  127. // GetRegisteredDrivers 返回当前注册表中所有数据库类型及其可用版本列表。
  128. // 返回值:map,键为数据库类型,值为该类型下已注册的版本切片,用于调试或展示。
  129. func GetRegisteredDrivers() map[string][]string {
  130. globalRegistry.mu.RLock()
  131. defer globalRegistry.mu.RUnlock()
  132. driversCopy := make(map[string][]string)
  133. for dbType, versions := range globalRegistry.drivers {
  134. for version := range versions {
  135. driversCopy[dbType] = append(driversCopy[dbType], version)
  136. }
  137. }
  138. return driversCopy
  139. }