github.com/erda-project/erda-infra@v1.0.10-0.20240327085753-f3a249292aeb/providers/mysqlxorm/xorm.go (about) 1 // Copyright (c) 2021 Terminus, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mysqlxorm 16 17 import ( 18 "context" 19 "fmt" 20 "reflect" 21 "time" 22 23 _ "github.com/go-sql-driver/mysql" // mysql client driver package 24 "xorm.io/xorm" 25 xormlog "xorm.io/xorm/log" 26 "xorm.io/xorm/names" 27 28 "github.com/erda-project/erda-infra/base/logs" 29 "github.com/erda-project/erda-infra/base/servicehub" 30 "github.com/erda-project/erda-infra/pkg/mysqldriver" 31 ) 32 33 // Interface . 34 type Interface interface { 35 DB() *xorm.Engine 36 NewSession(ops ...SessionOption) *Session 37 Close() error 38 DataSourceName() string 39 } 40 41 var ( 42 interfaceType = reflect.TypeOf((*Interface)(nil)).Elem() 43 xormType = reflect.TypeOf((*xorm.Engine)(nil)) 44 ) 45 46 type config struct { 47 MySQLURL string `file:"url" env:"MYSQL_URL"` 48 MySQLHost string `file:"host" env:"MYSQL_HOST" default:"localhost"` 49 MySQLPort string `file:"port" env:"MYSQL_PORT" default:"3306"` 50 MySQLUsername string `file:"username" env:"MYSQL_USERNAME" default:"root"` 51 MySQLPassword string `file:"password" env:"MYSQL_PASSWORD" default:""` 52 MySQLDatabase string `file:"database" env:"MYSQL_DATABASE"` 53 MySQLMaxIdleConns uint64 `file:"max_idle_conns" env:"MYSQL_MAXIDLECONNS" default:"10"` 54 MySQLMaxOpenConns uint64 `file:"max_open_conns" env:"MYSQL_MAXOPENCONNS" default:"20"` 55 MySQLMaxLifeTime time.Duration `file:"max_lifetime" env:"MYSQL_MAXLIFETIME" default:"30m"` 56 MySQLShowSQL bool `file:"show_sql" env:"MYSQL_SHOW_SQL" default:"false"` 57 MySQLProperties string `file:"properties" env:"MYSQL_PROPERTIES" default:"charset=utf8mb4&collation=utf8mb4_unicode_ci&parseTime=True&loc=Local"` 58 MySQLTLS string `file:"tls" env:"MYSQL_TLS"` 59 MySQLCaCertPath string `file:"ca_cert_path" env:"MYSQL_CACERTPATH"` 60 MySQLClientCertPath string `file:"client_cert_path" env:"MYSQL_CLIENTCERTPATH"` 61 MySQLClientKeyPath string `file:"client_key_path" env:"MYSQL_CLIENTKEYPATH"` 62 63 MySQLPingWhenInit bool `file:"ping_when_init" env:"MYSQL_PING_WHEN_INIT" default:"true"` 64 MySQLPingTimeoutSec uint64 `file:"ping_timeout_sec" env:"MYSQL_PING_TIMEOUT_SEC" default:"10"` 65 } 66 67 func (c *config) url() string { 68 if c.MySQLURL != "" { 69 return c.MySQLURL 70 } 71 72 url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?%s", 73 c.MySQLUsername, c.MySQLPassword, c.MySQLHost, c.MySQLPort, c.MySQLDatabase, c.MySQLProperties) 74 if c.MySQLTLS != "" { 75 url = fmt.Sprintf("%v&tls=%s", url, c.MySQLTLS) 76 } 77 return url 78 } 79 80 // provider . 81 type provider struct { 82 Cfg *config 83 Log logs.Logger 84 db *xorm.Engine 85 } 86 87 // Init . 88 func (p *provider) Init(ctx servicehub.Context) error { 89 err := mysqldriver.OpenTLS(p.Cfg.MySQLTLS, p.Cfg.MySQLCaCertPath, p.Cfg.MySQLClientCertPath, p.Cfg.MySQLClientKeyPath) 90 if err != nil { 91 return err 92 } 93 94 db, err := xorm.NewEngine("mysql", p.Cfg.url()) 95 if err != nil { 96 return fmt.Errorf("failed to connect to mysql server, err: %v", err) 97 } 98 99 db.SetMapper(names.GonicMapper{}) 100 if p.Cfg.MySQLShowSQL { 101 db.ShowSQL(true) 102 db.SetLogLevel(xormlog.LOG_DEBUG) 103 } 104 105 // connection pool 106 db.SetMaxIdleConns(int(p.Cfg.MySQLMaxIdleConns)) 107 db.SetMaxOpenConns(int(p.Cfg.MySQLMaxOpenConns)) 108 db.SetConnMaxLifetime(p.Cfg.MySQLMaxLifeTime) 109 db.SetDisableGlobalCache(true) 110 111 // ping when init 112 if p.Cfg.MySQLPingWhenInit { 113 ctxForPing, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(p.Cfg.MySQLPingTimeoutSec)) 114 defer cancel() 115 if err := db.PingContext(ctxForPing); err != nil { 116 return err 117 } 118 } 119 120 p.db = db 121 return nil 122 } 123 124 func (p *provider) DB() *xorm.Engine { return p.db } 125 126 func (p *provider) Provide(ctx servicehub.DependencyContext, args ...interface{}) interface{} { 127 if ctx.Service() == "mysql-xorm-client" || ctx.Type() == xormType { 128 return p.db 129 } 130 return p 131 } 132 133 func (p *provider) DataSourceName() string { 134 return p.DB().DataSourceName() 135 } 136 137 func (p *provider) Close() error { 138 return p.DB().Close() 139 } 140 141 func init() { 142 servicehub.Register("mysql-xorm", &servicehub.Spec{ 143 Services: []string{"mysql-xorm", "mysql-xorm-client"}, 144 Types: []reflect.Type{ 145 interfaceType, xormType, 146 }, 147 Description: "mysql-xorm", 148 ConfigFunc: func() interface{} { return &config{} }, 149 Creator: func() servicehub.Provider { 150 return &provider{} 151 }, 152 }) 153 }