add function Close for DB for package gdb

This commit is contained in:
John Guo
2021-08-24 22:59:25 +08:00
parent b129ee3f04
commit 29d50994ae
4 changed files with 42 additions and 44 deletions

View File

@ -73,6 +73,14 @@ type DB interface {
// Also see Core.Ctx.
Ctx(ctx context.Context) DB
// Close closes the database and prevents new queries from starting.
// Close then waits for all queries that have started processing on the server
// to finish.
//
// It is rare to Close a DB, as the DB handle is meant to be
// long-lived and shared between many goroutines.
Close(ctx context.Context) error
// ===========================================================================
// Query APIs.
// ===========================================================================
@ -94,7 +102,7 @@ type DB interface {
Delete(table string, condition interface{}, args ...interface{}) (sql.Result, error) // See Core.Delete.
// ===========================================================================
// Internal APIs for CURD, which can be overwrote for custom CURD implements.
// Internal APIs for CURD, which can be overwritten by custom CURD implements.
// ===========================================================================
DoGetAll(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoGetAll.
@ -179,6 +187,7 @@ type Core struct {
group string // Configuration group name.
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.StrAnyMap // links caches all created links by node.
schema *gtype.String // Custom schema for this object.
logger *glog.Logger // Logger for logging functionality.
config *ConfigNode // Current config node.
@ -302,9 +311,6 @@ var (
// in the field name as it conflicts with "db.table.field" pattern in SOME situations.
regularFieldNameWithoutDotRegPattern = `^[\w\-]+$`
// internalCache is the memory cache for internal usage.
internalCache = gcache.New()
// tableFieldsMap caches the table information retrived from database.
tableFieldsMap = gmap.New(true)
@ -347,6 +353,7 @@ func New(group ...string) (db DB, err error) {
group: groupName,
debug: gtype.NewBool(),
cache: gcache.New(),
links: gmap.NewStrAnyMap(true),
schema: gtype.NewString(),
logger: glog.New(),
config: node,
@ -441,7 +448,7 @@ func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
for i := 0; i < len(cg); i++ {
total += cg[i].Weight * 100
}
// If total is 0 means all of the nodes have no weight attribute configured.
// If total is 0 means all the nodes have no weight attribute configured.
// It then defaults each node's weight attribute to 1.
if total == 0 {
for i := 0; i < len(cg); i++ {
@ -490,7 +497,7 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error
node = &n
}
// Cache the underlying connection pool object by node.
v, _ := internalCache.GetOrSetFuncLock(node.String(), func() (interface{}, error) {
v := c.links.GetOrSetFuncLock(node.String(), func() interface{} {
intlog.Printf(
c.db.GetCtx(),
`open new connection, master:%#v, config:%#v, node:%#v`,
@ -510,7 +517,7 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error
sqlDb, err = c.db.Open(node)
if err != nil {
return nil, err
return nil
}
if c.config.MaxIdleConnCount > 0 {
@ -534,8 +541,8 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error
} else {
sqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime)
}
return sqlDb, nil
}, 0)
return sqlDb
})
if v != nil && sqlDb == nil {
sqlDb = v.(*sql.DB)
}

View File

@ -12,6 +12,7 @@ import (
"database/sql"
"fmt"
"github.com/gogf/gf/errors/gcode"
"github.com/gogf/gf/internal/intlog"
"reflect"
"strings"
@ -95,6 +96,27 @@ func (c *Core) GetCtxTimeout(timeoutType int, ctx context.Context) (context.Cont
return ctx, func() {}
}
// Close closes the database and prevents new queries from starting.
// Close then waits for all queries that have started processing on the server
// to finish.
//
// It is rare to Close a DB, as the DB handle is meant to be
// long-lived and shared between many goroutines.
func (c *Core) Close(ctx context.Context) (err error) {
c.links.LockFunc(func(m map[string]interface{}) {
for k, v := range m {
if db, ok := v.(*sql.DB); ok {
err = db.Close()
intlog.Printf(ctx, `close link: %s, err: %v`, k, err)
if err != nil {
return
}
}
}
})
return
}
// Master creates and returns a connection from master node if master-slave configured.
// It returns the default connection if master-slave not configured.
func (c *Core) Master(schema ...string) (*sql.DB, error) {

View File

@ -236,34 +236,6 @@ FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '%s' ORDER BY COLUMN_ID`,
return
}
func (d *DriverOracle) getTableUniqueIndex(table string) (fields map[string]map[string]string, err error) {
table = strings.ToUpper(table)
v, _ := internalCache.GetOrSetFunc(
"table_unique_index_"+table,
func() (interface{}, error) {
res := (Result)(nil)
res, err = d.db.GetAll(fmt.Sprintf(`
SELECT INDEX_NAME,COLUMN_NAME,CHAR_LENGTH FROM USER_IND_COLUMNS
WHERE TABLE_NAME = '%s'
AND INDEX_NAME IN(SELECT INDEX_NAME FROM USER_INDEXES WHERE TABLE_NAME='%s' AND UNIQUENESS='UNIQUE')
ORDER BY INDEX_NAME,COLUMN_POSITION`, table, table))
if err != nil {
return nil, err
}
fields := make(map[string]map[string]string)
for _, v := range res {
mm := make(map[string]string)
mm[v["COLUMN_NAME"].String()] = v["CHAR_LENGTH"].String()
fields[v["INDEX_NAME"].String()] = mm
}
return fields, nil
}, 0)
if err == nil {
fields = v.(map[string]map[string]string)
}
return
}
// DoInsert inserts or updates data for given table.
// This function is usually used for custom interface definition, you do not need call it manually.
// The parameter `data` can be type of map/gmap/struct/*struct/[]map/[]struct, etc.