目录1.Mysql-通过sql建立连接池2.mysql-gORM 建立连接池3.连接池相较于单个client4.通用连接池参考1.mysql-通过sql建立连接池 连接池用sql.Open函数创建连接池,可是此时只是初始
连接池用sql.Open函数创建连接池,可是此时只是初始化了连接池,并没有创建任何连接。连接创建都是惰性的,只有当你真正使用到连接的时候,连接池才会创建连接。连接池很重要,它直接影响着你的程序行为。
连接池的工作原来却相当简单。当你的函数(例如Exec,Query)调用需要访问底层数据库的时候,函数首先会向连接池请求一个连接。如果连接池有空闲的连接,则返回给函数。否则连接池将会创建一个新的连接给函数。一旦连接给了函数,连接则归属于函数。函数执行完毕后,要不把连接所属权归还给连接池,要么传递给下一个需要连接的(Rows)对象,最后使用完连接的对象也会把连接释放回到连接池。
请求一个连接的函数有好几种,执行完毕处理连接的方式稍有差别,大致如下:
因为每一个连接都是惰性创建的,如何验证sql.Open调用之后,sql.DB对象可用呢?通常使用db.Ping()方法初始化,调用了Ping之后,连接池一定会初始化一个数据库连接。
连接失败关于连接池另外一个知识点就是你不必检查或者尝试处理连接失败的情况。当你进行数据库操作的时候,如果连接失败了,database/sql会帮你处理。实际上,当从连接池取出的连接断开的时候,database/sql会自动尝试重连10次。仍然无法重连的情况下会自动从连接池再获取一个或者新建另外一个。
连接池配置配置连接池有两个的方法:
对于连接池的使用依赖于你是如何配置连接池,如果使用不当会导致下面问题:
数据库标准接口里面有3个方法用于设置连接池的属性: SetConnMaxLifetime, SetMaxIdleConns, SetMaxOpenConns
项目结构
代码pool
package pool
import (
"database/sql"
"fmt"
_ "GitHub.com/go-sql-driver/mysql"
"log"
"time"
)
var DB *sql.DB
func init() {
DB, _ = sql.Open("mysql", "root:root@tcp(localhost:3306)/test?charset=utf8&parseTime=True&loc=Local") // 使用本地时间,即东八区,北京时间
// set pool params
DB.SetMaxOpenConns(2000)
DB.SetMaxIdleConns(1000)
DB.SetConnMaxLifetime(time.Minute * 60) // mysql default conn timeout=8h, should < mysql_timeout
err := DB.Ping()
if err != nil {
log.Fatalf("database init failed, err: ", err)
}
log.Println("mysql conn pool has initiated.")
}
func checkErr(err error) {
if err != nil {
log.Println(err)
panic(err)
}
}
func createTable() {
db := DB
table := `CREATE TABLE IF NOT EXISTS test.user (
user_id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户编号',
user_name VARCHAR(45) NOT NULL COMMENT '用户名称',
user_age TINYINT(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT '用户年龄',
user_sex TINYINT(3) UNSIGNED NOT NULL DEFAULT 0 COMMENT '用户性别',
PRIMARY KEY (user_id))
ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARACTER SET = utf8
COLLATE = utf8_general_ci
COMMENT = '用户表'`
if _, err := db.Exec(table); err != nil {
checkErr(err)
}
}
func insert() {
db := DB
stmt, err := db.Prepare(`INSERT user (user, age) values (?, ?)`)
checkErr(err)
res, err := stmt.Exec("Elvis", 26)
checkErr(err)
id, err := res.LastInsertId()
checkErr(err)
log.Println(id)
}
func query() {
db := DB
rows, err := db.Query("SELECT * FROM user")
checkErr(err)
for rows.Next() {
var userId int
var userName string
var userAge int
var userSex int
rows.Columns()
err = rows.Scan(&userId, &userName, &userAge, &userSex)
checkErr(err)
fmt.Println(userId)
fmt.Println(userName)
fmt.Println(userAge)
fmt.Println(userSex)
}
}
func queryToMap() {
db := DB
rows, err := db.Query("SELECT * FROM user")
checkErr(err)
//字典类型
//构造scanArgs、values两个数组,scanArgs的每个值指向values相应值的地址
columns, _ := rows.Columns()
scanArgs := make([]interface{}, len(columns))
values := make([]interface{}, len(columns))
for i := range values {
scanArgs[i] = &values[i]
}
for rows.Next() {
//将行数据保存到record字典
err = rows.Scan(scanArgs...)
record := make(map[string]string)
for i, col := range values {
if col != nil {
record[columns[i]] = string(col.([]byte))
}
}
fmt.Println(record)
}
}
func update() {
db := DB
stmt, err := db.Prepare(`UPDATE user SET user_age=?,user_sex=? WHERE user_id=?`)
checkErr(err)
res, err := stmt.Exec(21, 2, 1)
checkErr(err)
num, err := res.RowsAffected()
checkErr(err)
fmt.Println(num)
}
func remove() {
db := DB
stmt, err := db.Prepare(`DELETE FROM user WHERE user_id=?`)
checkErr(err)
res, err := stmt.Exec(1)
checkErr(err)
num, err := res.RowsAffected()
checkErr(err)
fmt.Println(num)
}
main
package main
import (
"fmt"
"log"
"net/Http"
. "go-mysql-pool-v1/pool"
)
func main() {
http.HandleFunc("/pool", pool)
log.Println("server is up now...")
http.ListenAndServe(":8080", nil)
}
func pool(w http.ResponseWriter, r *http.Request) {
rows, err := DB.Query(`select * from user limit 1`)
defer rows.Close()
checkErr(err)
columns, _ := rows.Columns()
scanArgs := make([]interface{}, len(columns))
values := make([]interface{}, len(columns))
for j := range values {
scanArgs[j] = &values[j]
}
record := make(map[string]string)
for rows.Next() {
err = rows.Scan(scanArgs...)
for i, col := range values {
if col != nil {
record[columns[i]] = string(col.([]byte))
}
}
}
log.Println(record)
fmt.Fprintf(w, "finish")
}
func checkErr(err error) {
if err != nil {
log.Println(err)
panic(err)
}
}
其实gorm的连接池设置,底层还是用的database/sql的设置连接池的方法,无非就是加一层gorm自身的一些设置。
以下示例为gorm v2版本,v1版本通过github.com/jinzhu/gorm,如mysql的驱动导入需要加_
。
代码结构
.
+--- config
| +--- config.go
| +--- config.JSON
+--- go.mod
+--- go.sum
+--- main.go
+--- pool
| +--- gorm-pool.go
+--- test.db
config.json
{
"database": {
"name": "test",
"type": "mysql",
"host": "localhost",
"port": "3306",
"user": "root",
"passWord": "root",
"table_prefix": ""
}
}
config.go
package config
import (
"encoding/json"
"os"
)
type Database struct {
Type string `json:"type"`
Host string `json:"host"`
Port string `json:"port"`
User string `json:"user"`
Password string `json:"password"`
Name string `json:"name"`
TablePrefix string `json:"table_prefix"`
}
var DatabaseSetting = &Database{}
type Config struct {
Database *Database `json:"database"`
}
var GlobalConfigSetting = &Config{}
func init() {
// win path is abs-path, linux -> config.json
filePtr, err := os.Open("D:\\demo1\\src\\demo\\demo06\\go-mysql-pool-v2\\config\\config.json")
if err != nil {
return
}
defer filePtr.Close()
// json decode
decoder := json.NewDecoder(filePtr)
err = decoder.Decode(GlobalConfigSetting)
DatabaseSetting = GlobalConfigSetting.Database
}
gorm-pool.go
注意设置表前缀和单复数
package pool
import (
"fmt"
"go-mysql-pool-v2/config"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/driver/SQLite"
"gorm.io/gorm"
"gorm.io/gorm/schema"
"log"
"time"
)
var db *gorm.DB
// gorm v2
func init() {
var dbURi string
var dialector gorm.Dialector
if config.DatabaseSetting.Type == "mysql" {
dbURi = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=true",
config.DatabaseSetting.User,
config.DatabaseSetting.Password,
config.DatabaseSetting.Host,
config.DatabaseSetting.Port,
config.DatabaseSetting.Name)
dialector = mysql.New(mysql.Config{
DSN: dbURi, // data source name
DefaultStringSize: 256, // default size for string fields
DisableDatetimePrecision: true, // disable datetime precision, which not supported before MySQL 5.6
DontSupportRenameIndex: true, // drop & create when rename index, rename index not supported before MySQL 5.7, mariadb
DontSupportRenameColumn: true, // `change` when rename column, rename column not supported before MySQL 8, MariaDB
SkipInitializeWithVersion: false, // auto configure based on currently MySQL version
})
} else if config.DatabaseSetting.Type == "postgres" {
dbURi = fmt.Sprintf("host=%s port=%s user=%s dbname=%s sslmode=disable password=%s",
config.DatabaseSetting.Host,
config.DatabaseSetting.Port,
config.DatabaseSetting.User,
config.DatabaseSetting.Name,
config.DatabaseSetting.Password)
dialector = postgres.New(postgres.Config{
DSN: "user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai",
PreferSimpleProtocol: true, // disables implicit prepared statement usage
})
} else { // sqlite3
dbURi = fmt.Sprintf("test.db")
dialector = sqlite.Open("test.db")
}
conn, err := gorm.Open(dialector, &gorm.Config{ // 如果不用设置表前缀及复数,nil
NamingStrategy: schema.NamingStrategy{
TablePrefix: config.DatabaseSetting.TablePrefix, // set table prefix
SingularTable: true, // set table singular
},
})
if err != nil {
log.Println(err.Error())
}
sqlDB, err := conn.DB()
if err != nil {
log.Println("connect db server failed.")
}
sqlDB.SetMaxOpenConns(100)
sqlDB.SetMaxIdleConns(10)
sqlDB.SetConnMaxLifetime(600*time.Second)
db = conn
}
// open api
func GetDB() *gorm.DB {
sqlDB, err := db.DB()
if err != nil {
log.Println("connect db server failed.")
}
if err = sqlDB.Ping(); err != nil {
sqlDB.Close()
}
return db
}
main
package main
import (
"go-mysql-pool-v2/pool"
"gorm.io/gorm"
"log"
)
type Product struct {
gorm.Model // default add id stats time, id as primary key
Code string
Price uint
}
func main() {
log.Println("gorm init...")
SetupModel()
}
func SetupModel() {
db := pool.GetDB()
// auto migrate
db.AutoMigrate(&Product{})
// create record
db.Create(&Product{Code: "L1212", Price: 1000})
}
go.mod
module go-mysql-pool-v2
go 1.16
replace go-mysql-pool-v2 => ../go-mysql-pool-v2
require (
gorm.io/driver/mysql v1.3.4
gorm.io/driver/postgres v1.3.4
gorm.io/driver/sqlite v1.3.4
gorm.io/gorm v1.23.5
)
注
ubuntu安装ab工具,apt-get install apache2-utils
// get 一般请求
ab -n 1000 -c 1000 http://xxx
// post json请求
ab -n 100000 -c 400 -p tempPara.txt -T application/json http://xxx
tempPara.txt内容:
{"driverId": 17,"pageNo": 1,"pageSize": 20,"status": 1}
到此这篇关于golang mysql的连接池的具体使用的文章就介绍到这了,更多相关golang mysql连接池内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!
--结束END--
本文标题: golang mysql的连接池的具体使用
本文链接: https://www.lsjlt.com/news/196862.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
下载Word文档到电脑,方便收藏和打印~
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
2024-05-15
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0