mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
fix issue 1915 and repeated link instance key for package gdb (#2250)
* fix issue #1915 * fix issue in repeated link instance key * add configuration item Namespace for package gdb * up * up * fix: pgsql list table names (#2255) Co-authored-by: Gin <qinyuguang@gmail.com>
This commit is contained in:
@ -179,15 +179,22 @@ type DB 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.StrAnyMap // links caches all created links by node.
|
||||
logger glog.ILogger // Logger for logging functionality.
|
||||
config *ConfigNode // Current config node.
|
||||
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.StrAnyMap // links caches all created links by node.
|
||||
logger glog.ILogger // Logger for logging functionality.
|
||||
config *ConfigNode // Current config node.
|
||||
dynamicConfig dynamicConfig // Dynamic configurations, which can be changed in runtime.
|
||||
}
|
||||
|
||||
type dynamicConfig struct {
|
||||
MaxIdleConnCount int
|
||||
MaxOpenConnCount int
|
||||
MaxConnLifeTime time.Duration
|
||||
}
|
||||
|
||||
// DoCommitInput is the input parameters for function DoCommit.
|
||||
@ -237,6 +244,7 @@ type Sql struct {
|
||||
Start int64 // Start execution timestamp in milliseconds.
|
||||
End int64 // End execution timestamp in milliseconds.
|
||||
Group string // Group is the group name of the configuration that the sql is executed from.
|
||||
Schema string // Schema is the schema name of the configuration that the sql is executed from.
|
||||
IsTransaction bool // IsTransaction marks whether this sql is executed in transaction.
|
||||
RowsAffected int64 // RowsAffected marks retrieved or affected number with current sql statement.
|
||||
}
|
||||
@ -424,6 +432,10 @@ func NewByGroup(group ...string) (db DB, err error) {
|
||||
}
|
||||
|
||||
// newDBByConfigNode creates and returns an ORM object with given configuration node and group name.
|
||||
//
|
||||
// Very Note:
|
||||
// The parameter `node` is used for DB creation, not for underlying connection creation.
|
||||
// So all db type configurations in the same group should be the same.
|
||||
func newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) {
|
||||
if node.Link != "" {
|
||||
node = parseConfigNodeLink(node)
|
||||
@ -435,6 +447,11 @@ func newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) {
|
||||
links: gmap.NewStrAnyMap(true),
|
||||
logger: glog.New(),
|
||||
config: node,
|
||||
dynamicConfig: dynamicConfig{
|
||||
MaxIdleConnCount: node.MaxIdleConnCount,
|
||||
MaxOpenConnCount: node.MaxOpenConnCount,
|
||||
MaxConnLifeTime: node.MaxConnLifeTime,
|
||||
},
|
||||
}
|
||||
if v, ok := driverMap[node.Type]; ok {
|
||||
if c.db, err = v.New(c, node); err != nil {
|
||||
@ -538,7 +555,9 @@ func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
|
||||
for i := 0; i < len(cg); i++ {
|
||||
max = min + cg[i].Weight*100
|
||||
if random >= min && random < max {
|
||||
// Return a copy of the ConfigNode.
|
||||
// ====================================================
|
||||
// Return a COPY of the ConfigNode.
|
||||
// ====================================================
|
||||
node := ConfigNode{}
|
||||
node = cg[i]
|
||||
return &node
|
||||
@ -552,17 +571,23 @@ func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
|
||||
// The parameter `master` specifies whether retrieves master node connection if
|
||||
// master-slave nodes are configured.
|
||||
func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {
|
||||
var node *ConfigNode
|
||||
// Load balance.
|
||||
var (
|
||||
node *ConfigNode
|
||||
ctx = c.db.GetCtx()
|
||||
)
|
||||
if c.group != "" {
|
||||
// Load balance.
|
||||
configs.RLock()
|
||||
defer configs.RUnlock()
|
||||
// Value COPY for node.
|
||||
node, err = getConfigNodeByGroup(c.group, master)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
node = c.config
|
||||
// Value COPY for node.
|
||||
n := *c.db.GetConfig()
|
||||
node = &n
|
||||
}
|
||||
if node.Charset == "" {
|
||||
node.Charset = defaultCharset
|
||||
@ -570,42 +595,42 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error
|
||||
// Changes the schema.
|
||||
nodeSchema := gutil.GetOrDefaultStr(c.schema, schema...)
|
||||
if nodeSchema != "" {
|
||||
// Value copy.
|
||||
n := *node
|
||||
n.Name = nodeSchema
|
||||
node = &n
|
||||
node.Name = nodeSchema
|
||||
}
|
||||
// Update the configuration object in internal data.
|
||||
internalData := c.GetInternalCtxDataFromCtx(ctx)
|
||||
if internalData != nil {
|
||||
internalData.ConfigNode = node
|
||||
}
|
||||
// Cache the underlying connection pool object by node.
|
||||
instanceNameByNode := fmt.Sprintf(
|
||||
`%s@%s(%s:%s)/%s`,
|
||||
node.User, node.Protocol, node.Host, node.Port, node.Name,
|
||||
)
|
||||
v := c.links.GetOrSetFuncLock(instanceNameByNode, func() interface{} {
|
||||
instanceNameByNode := fmt.Sprintf(`%+v`, node)
|
||||
instanceValue := c.links.GetOrSetFuncLock(instanceNameByNode, func() interface{} {
|
||||
if sqlDb, err = c.db.Open(node); err != nil {
|
||||
return nil
|
||||
}
|
||||
if sqlDb == nil {
|
||||
return nil
|
||||
}
|
||||
if c.config.MaxIdleConnCount > 0 {
|
||||
sqlDb.SetMaxIdleConns(c.config.MaxIdleConnCount)
|
||||
if c.dynamicConfig.MaxIdleConnCount > 0 {
|
||||
sqlDb.SetMaxIdleConns(c.dynamicConfig.MaxIdleConnCount)
|
||||
} else {
|
||||
sqlDb.SetMaxIdleConns(defaultMaxIdleConnCount)
|
||||
}
|
||||
if c.config.MaxOpenConnCount > 0 {
|
||||
sqlDb.SetMaxOpenConns(c.config.MaxOpenConnCount)
|
||||
if c.dynamicConfig.MaxOpenConnCount > 0 {
|
||||
sqlDb.SetMaxOpenConns(c.dynamicConfig.MaxOpenConnCount)
|
||||
} else {
|
||||
sqlDb.SetMaxOpenConns(defaultMaxOpenConnCount)
|
||||
}
|
||||
if c.config.MaxConnLifeTime > 0 {
|
||||
sqlDb.SetConnMaxLifetime(c.config.MaxConnLifeTime)
|
||||
if c.dynamicConfig.MaxConnLifeTime > 0 {
|
||||
sqlDb.SetConnMaxLifetime(c.dynamicConfig.MaxConnLifeTime)
|
||||
} else {
|
||||
sqlDb.SetConnMaxLifetime(defaultMaxConnLifeTime)
|
||||
}
|
||||
return sqlDb
|
||||
})
|
||||
if v != nil && sqlDb == nil {
|
||||
sqlDb = v.(*sql.DB)
|
||||
if instanceValue != nil && sqlDb == nil {
|
||||
// It reads from instance map.
|
||||
sqlDb = instanceValue.(*sql.DB)
|
||||
}
|
||||
if node.Debug {
|
||||
c.db.SetDebug(node.Debug)
|
||||
|
||||
@ -665,15 +665,9 @@ func (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) {
|
||||
transactionIdStr = fmt.Sprintf(`[txid:%d] `, v.(uint64))
|
||||
}
|
||||
}
|
||||
// Runtime schema.
|
||||
schemaName := c.GetSchema()
|
||||
if schemaName == "" {
|
||||
// The original schema in configuration.
|
||||
schemaName = c.config.Name
|
||||
}
|
||||
s := fmt.Sprintf(
|
||||
"[%3d ms] [%s] [%s] [rows:%-3d] %s%s",
|
||||
sql.End-sql.Start, sql.Group, schemaName, sql.RowsAffected, transactionIdStr, sql.Format,
|
||||
sql.End-sql.Start, sql.Group, sql.Schema, sql.RowsAffected, transactionIdStr, sql.Format,
|
||||
)
|
||||
if sql.Error != nil {
|
||||
s += "\nError: " + sql.Error.Error()
|
||||
|
||||
@ -41,13 +41,14 @@ type ConfigNode struct {
|
||||
Charset string `json:"charset"` // (Optional, "utf8mb4" in default) Custom charset when operating on database.
|
||||
Protocol string `json:"protocol"` // (Optional, "tcp" in default) See net.Dial for more information which networks are available.
|
||||
Timezone string `json:"timezone"` // (Optional) Sets the time zone for displaying and interpreting time stamps.
|
||||
Namespace string `json:"namespace"` // Namespace for some databases. Eg, in pgsql, the `Name` acts as the `catalog`, the `NameSpace` acts as the `schema`.
|
||||
MaxIdleConnCount int `json:"maxIdle"` // (Optional) Max idle connection configuration for underlying connection pool.
|
||||
MaxOpenConnCount int `json:"maxOpen"` // (Optional) Max open connection configuration for underlying connection pool.
|
||||
MaxConnLifeTime time.Duration `json:"maxLifeTime"` // (Optional) Max amount of time a connection may be idle before being closed.
|
||||
QueryTimeout time.Duration `json:"queryTimeout"` // (Optional) Max query time for per dql.
|
||||
ExecTimeout time.Duration `json:"execTimeout"` // (Optional) Max exec time for dml.
|
||||
TranTimeout time.Duration `json:"tranTimeout"` // (Optional) Max exec time time for a transaction.
|
||||
PrepareTimeout time.Duration `json:"prepareTimeout"` // (Optional) Max exec time time for prepare operation.
|
||||
TranTimeout time.Duration `json:"tranTimeout"` // (Optional) Max exec time for a transaction.
|
||||
PrepareTimeout time.Duration `json:"prepareTimeout"` // (Optional) Max exec time for prepare operation.
|
||||
CreatedAt string `json:"createdAt"` // (Optional) The filed name of table for automatic-filled created datetime.
|
||||
UpdatedAt string `json:"updatedAt"` // (Optional) The filed name of table for automatic-filled updated datetime.
|
||||
DeletedAt string `json:"deletedAt"` // (Optional) The filed name of table for automatic-filled updated datetime.
|
||||
@ -181,7 +182,7 @@ func (c *Core) GetLogger() glog.ILogger {
|
||||
// The default max idle connections is currently 2. This may change in
|
||||
// a future release.
|
||||
func (c *Core) SetMaxIdleConnCount(n int) {
|
||||
c.config.MaxIdleConnCount = n
|
||||
c.dynamicConfig.MaxIdleConnCount = n
|
||||
}
|
||||
|
||||
// SetMaxOpenConnCount sets the maximum number of open connections to the database.
|
||||
@ -193,7 +194,7 @@ func (c *Core) SetMaxIdleConnCount(n int) {
|
||||
// If n <= 0, then there is no limit on the number of open connections.
|
||||
// The default is 0 (unlimited).
|
||||
func (c *Core) SetMaxOpenConnCount(n int) {
|
||||
c.config.MaxOpenConnCount = n
|
||||
c.dynamicConfig.MaxOpenConnCount = n
|
||||
}
|
||||
|
||||
// SetMaxConnLifeTime sets the maximum amount of time a connection may be reused.
|
||||
@ -202,11 +203,15 @@ func (c *Core) SetMaxOpenConnCount(n int) {
|
||||
//
|
||||
// If d <= 0, connections are not closed due to a connection's age.
|
||||
func (c *Core) SetMaxConnLifeTime(d time.Duration) {
|
||||
c.config.MaxConnLifeTime = d
|
||||
c.dynamicConfig.MaxConnLifeTime = d
|
||||
}
|
||||
|
||||
// GetConfig returns the current used node configuration.
|
||||
func (c *Core) GetConfig() *ConfigNode {
|
||||
internalData := c.GetInternalCtxDataFromCtx(c.db.GetCtx())
|
||||
if internalData != nil && internalData.ConfigNode != nil {
|
||||
return internalData.ConfigNode
|
||||
}
|
||||
return c.config
|
||||
}
|
||||
|
||||
@ -247,7 +252,11 @@ func (c *Core) GetPrefix() string {
|
||||
|
||||
// GetSchema returns the schema configured.
|
||||
func (c *Core) GetSchema() string {
|
||||
return c.schema
|
||||
schema := c.schema
|
||||
if schema == "" {
|
||||
schema = c.db.GetConfig().Name
|
||||
}
|
||||
return schema
|
||||
}
|
||||
|
||||
func parseConfigNodeLink(node *ConfigNode) *ConfigNode {
|
||||
|
||||
@ -17,6 +17,9 @@ type internalCtxData struct {
|
||||
// Operation DB.
|
||||
DB DB
|
||||
|
||||
// Used configuration node in current operation.
|
||||
ConfigNode *ConfigNode
|
||||
|
||||
// The first column in result response from database server.
|
||||
// This attribute is used for Value/Count selection statement purpose,
|
||||
// which is to avoid HOOK handler that might modify the result columns
|
||||
|
||||
@ -48,8 +48,8 @@ func (c *Core) DoQuery(ctx context.Context, link Link, sql string, args ...inter
|
||||
}
|
||||
}
|
||||
|
||||
if c.GetConfig().QueryTimeout > 0 {
|
||||
ctx, _ = context.WithTimeout(ctx, c.GetConfig().QueryTimeout)
|
||||
if c.db.GetConfig().QueryTimeout > 0 {
|
||||
ctx, _ = context.WithTimeout(ctx, c.db.GetConfig().QueryTimeout)
|
||||
}
|
||||
|
||||
// Sql filtering.
|
||||
@ -107,9 +107,9 @@ func (c *Core) DoExec(ctx context.Context, link Link, sql string, args ...interf
|
||||
}
|
||||
}
|
||||
|
||||
if c.GetConfig().ExecTimeout > 0 {
|
||||
if c.db.GetConfig().ExecTimeout > 0 {
|
||||
var cancelFunc context.CancelFunc
|
||||
ctx, cancelFunc = context.WithTimeout(ctx, c.GetConfig().ExecTimeout)
|
||||
ctx, cancelFunc = context.WithTimeout(ctx, c.db.GetConfig().ExecTimeout)
|
||||
defer cancelFunc()
|
||||
}
|
||||
|
||||
@ -264,6 +264,7 @@ func (c *Core) DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutp
|
||||
Start: timestampMilli1,
|
||||
End: timestampMilli2,
|
||||
Group: c.db.GetGroup(),
|
||||
Schema: c.db.GetSchema(),
|
||||
RowsAffected: rowsAffected,
|
||||
IsTransaction: in.IsTransaction,
|
||||
}
|
||||
@ -333,9 +334,9 @@ func (c *Core) DoPrepare(ctx context.Context, link Link, sql string) (stmt *Stmt
|
||||
}
|
||||
}
|
||||
|
||||
if c.GetConfig().PrepareTimeout > 0 {
|
||||
if c.db.GetConfig().PrepareTimeout > 0 {
|
||||
// DO NOT USE cancel function in prepare statement.
|
||||
ctx, _ = context.WithTimeout(ctx, c.GetConfig().PrepareTimeout)
|
||||
ctx, _ = context.WithTimeout(ctx, c.db.GetConfig().PrepareTimeout)
|
||||
}
|
||||
|
||||
// Link execution.
|
||||
|
||||
@ -14,6 +14,7 @@ import (
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
)
|
||||
|
||||
// CacheOption is options for model cache control in query.
|
||||
type CacheOption struct {
|
||||
// Duration is the TTL for the cache.
|
||||
// If the parameter `Duration` < 0, which means it clear the cache with given `Name`.
|
||||
|
||||
Reference in New Issue
Block a user