refactor(database): 优化数据库连接管理实现

- 修改 RegisterNilChecker 方法返回实例以支持链式调用
- 更新 Core 结构体中 links 字段类型为类型安全的 KVMap
- 添加专门的链接检查器函数用于连接池管理
- 使用泛型 KVMap 替代原始 map 类型提升类型安全性
- 简化连接关闭逻辑并移除不必要的类型断言
- 优化统计功能中的迭代器实现提高性能
This commit is contained in:
shanyujie
2026-01-19 17:38:49 +08:00
parent 5e677a1e05
commit 465324551a
9 changed files with 42 additions and 39 deletions

View File

@ -66,10 +66,11 @@ func NewKVMapWithCheckerFrom[K comparable, V any](data map[K]V, checker NilCheck
// This function is used to determine if a value should be considered as nil.
// The nil checker function takes a value of type V and returns a boolean indicating
// whether the value should be treated as nil.
func (m *KVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) {
func (m *KVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *KVMap[K, V] {
m.mu.Lock()
defer m.mu.Unlock()
m.nilChecker = nilChecker
return m
}
// isNil checks whether the given value is nil.

View File

@ -85,10 +85,11 @@ func NewListKVMapWithCheckerFrom[K comparable, V any](data map[K]V, nilChecker N
// This function is used to determine if a value should be considered as nil.
// The nil checker function takes a value of type V and returns a boolean indicating
// whether the value should be treated as nil.
func (m *ListKVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) {
func (m *ListKVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *ListKVMap[K, V] {
m.mu.Lock()
defer m.mu.Unlock()
m.nilChecker = nilChecker
return m
}
// isNil checks whether the given value is nil.

View File

@ -70,10 +70,11 @@ func NewTSetWithCheckerFrom[T comparable](items []T, checker NilChecker[T], safe
// This function is used to determine if an element should be considered as nil.
// The nil checker function takes an element of type T and returns a boolean indicating
// whether the element should be treated as nil.
func (set *TSet[T]) RegisterNilChecker(nilChecker NilChecker[T]) {
func (set *TSet[T]) RegisterNilChecker(nilChecker NilChecker[T]) *TSet[T] {
set.mu.Lock()
defer set.mu.Unlock()
set.nilChecker = nilChecker
return set
}
// isNil checks whether the given value is nil.

View File

@ -82,10 +82,11 @@ func NewAVLKVTreeWithCheckerFrom[K comparable, V any](comparator func(v1, v2 K)
// This function is used to determine if a value should be considered as nil.
// The nil checker function takes a value of type V and returns a boolean indicating
// whether the value should be treated as nil.
func (tree *AVLKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) {
func (tree *AVLKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *AVLKVTree[K, V] {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.nilChecker = nilChecker
return tree
}
// isNil checks whether the given value is nil.

View File

@ -81,10 +81,11 @@ func NewBKVTreeWithCheckerFrom[K comparable, V any](m int, comparator func(v1, v
// This function is used to determine if a value should be considered as nil.
// The nil checker function takes a value of type V and returns a boolean indicating
// whether the value should be treated as nil.
func (tree *BKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) {
func (tree *BKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *BKVTree[K, V] {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.nilChecker = nilChecker
return tree
}
// isNil checks whether the given value is nil.

View File

@ -100,10 +100,11 @@ func RedBlackKVTreeInitFrom[K comparable, V any](tree *RedBlackKVTree[K, V], com
// This function is used to determine if a value should be considered as nil.
// The nil checker function takes a value of type V and returns a boolean indicating
// whether the value should be treated as nil.
func (tree *RedBlackKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) {
func (tree *RedBlackKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *RedBlackKVTree[K, V] {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.nilChecker = nilChecker
return tree
}
// isNil checks whether the given value is nil.

View File

@ -513,18 +513,18 @@ type StatsItem interface {
// Core is the base struct for database management.
type Core struct {
db DB // DB interface object.
ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization.
group string // Configuration group name.
schema string // Custom schema for this object.
debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime.
cache *gcache.Cache // Cache manager, SQL result cache only.
links *gmap.Map // links caches all created links by node.
logger glog.ILogger // Logger for logging functionality.
config *ConfigNode // Current config node.
localTypeMap *gmap.StrAnyMap // Local type map for database field type conversion.
dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime.
innerMemCache *gcache.Cache // Internal memory cache for storing temporary data.
db DB // DB interface object.
ctx context.Context // Context for chaining operation only. Do not set a default value in Core initialization.
group string // Configuration group name.
schema string // Custom schema for this object.
debug *gtype.Bool // Enable debug mode for the database, which can be changed in runtime.
cache *gcache.Cache // Cache manager, SQL result cache only.
links *gmap.KVMap[ConfigNode, *sql.DB] // links caches all created links by node.
logger glog.ILogger // Logger for logging functionality.
config *ConfigNode // Current config node.
localTypeMap *gmap.StrAnyMap // Local type map for database field type conversion.
dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime.
innerMemCache *gcache.Cache // Internal memory cache for storing temporary data.
}
type dynamicConfig struct {
@ -944,6 +944,9 @@ func NewByGroup(group ...string) (db DB, err error) {
)
}
// linksChecker is the checker function for links map.
var linksChecker = func(v *sql.DB) bool { return v == nil }
// newDBByConfigNode creates and returns an ORM object with given configuration node and group name.
//
// Very Note:
@ -960,7 +963,7 @@ func newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) {
group: group,
debug: gtype.NewBool(),
cache: gcache.New(),
links: gmap.New(true),
links: gmap.NewKVMapWithChecker[ConfigNode, *sql.DB](linksChecker, true),
logger: glog.New(),
config: node,
localTypeMap: gmap.NewStrAnyMap(true),
@ -1127,7 +1130,7 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error
// Cache the underlying connection pool object by node.
var (
instanceCacheFunc = func() any {
instanceCacheFunc = func() *sql.DB {
if sqlDb, err = c.db.Open(node); err != nil {
return nil
}
@ -1159,7 +1162,7 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error
)
if instanceValue != nil && sqlDb == nil {
// It reads from instance map.
sqlDb = instanceValue.(*sql.DB)
sqlDb = instanceValue
}
if node.Debug {
c.db.SetDebug(node.Debug)

View File

@ -113,19 +113,17 @@ func (c *Core) Close(ctx context.Context) (err error) {
if err = c.cache.Close(ctx); err != nil {
return err
}
c.links.LockFunc(func(m map[any]any) {
c.links.LockFunc(func(m map[ConfigNode]*sql.DB) {
for k, v := range m {
if db, ok := v.(*sql.DB); ok {
err = db.Close()
if err != nil {
err = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`)
}
intlog.Printf(ctx, `close link: %s, err: %v`, k, err)
if err != nil {
return
}
delete(m, k)
err = v.Close()
if err != nil {
err = gerror.WrapCode(gcode.CodeDbOperationError, err, `db.Close failed`)
}
intlog.Printf(ctx, `close link: %s, err: %v`, k, err)
if err != nil {
return
}
delete(m, k)
}
})
return

View File

@ -30,14 +30,10 @@ func (item *localStatsItem) Stats() sql.DBStats {
// Stats retrieves and returns the pool stat for all nodes that have been established.
func (c *Core) Stats(ctx context.Context) []StatsItem {
var items = make([]StatsItem, 0)
c.links.Iterator(func(k, v any) bool {
var (
node = k.(ConfigNode)
sqlDB = v.(*sql.DB)
)
c.links.Iterator(func(k ConfigNode, v *sql.DB) bool {
items = append(items, &localStatsItem{
node: &node,
stats: sqlDB.Stats(),
node: &k,
stats: v.Stats(),
})
return true
})