mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
refactor(database): 优化数据库连接管理实现
- 修改 RegisterNilChecker 方法返回实例以支持链式调用 - 更新 Core 结构体中 links 字段类型为类型安全的 KVMap - 添加专门的链接检查器函数用于连接池管理 - 使用泛型 KVMap 替代原始 map 类型提升类型安全性 - 简化连接关闭逻辑并移除不必要的类型断言 - 优化统计功能中的迭代器实现提高性能
This commit is contained in:
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user