iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >golang mysql的连接池的具体使用
  • 777
分享到

golang mysql的连接池的具体使用

golangmysql连接池golang连接池 2023-02-21 11:02:08 777人浏览 八月长安
摘要

目录1.Mysql-通过sql建立连接池2.mysql-gORM 建立连接池3.连接池相较于单个client4.通用连接池参考1.mysql-通过sql建立连接池 连接池用sql.Open函数创建连接池,可是此时只是初始

1.mysql-通过sql建立连接池

连接池用sql.Open函数创建连接池,可是此时只是初始化了连接池,并没有创建任何连接。连接创建都是惰性的,只有当你真正使用到连接的时候,连接池才会创建连接。连接池很重要,它直接影响着你的程序行为。

连接池的工作原来却相当简单。当你的函数(例如Exec,Query)调用需要访问底层数据库的时候,函数首先会向连接池请求一个连接。如果连接池有空闲的连接,则返回给函数。否则连接池将会创建一个新的连接给函数。一旦连接给了函数,连接则归属于函数。函数执行完毕后,要不把连接所属权归还给连接池,要么传递给下一个需要连接的(Rows)对象,最后使用完连接的对象也会把连接释放回到连接池。

请求一个连接的函数有好几种,执行完毕处理连接的方式稍有差别,大致如下:

  • db.Ping() 调用完毕后会马上把连接返回给连接池。
  • db.Exec() 调用完毕后会马上把连接返回给连接池,但是它返回的Result对象还保留这连接的引用,当后面的代码需要处理结果集的时候连接将会被重用。
  • db.Query() 调用完毕后会将连接传递给sql.Rows类型,当然后者迭代完毕或者显示的调用.Clonse()方法后,连接将会被释放回到连接池。
  • db.QueryRow()调用完毕后会将连接传递给sql.Row类型,当.Scan()方法调用之后把连接释放回到连接池。
  • db.Begin() 调用完毕后将连接传递给sql.Tx类型对象,当.Commit()或.Rollback()方法调用后释放连接。

因为每一个连接都是惰性创建的,如何验证sql.Open调用之后,sql.DB对象可用呢?通常使用db.Ping()方法初始化,调用了Ping之后,连接池一定会初始化一个数据库连接。

连接失败关于连接池另外一个知识点就是你不必检查或者尝试处理连接失败的情况。当你进行数据库操作的时候,如果连接失败了,database/sql会帮你处理。实际上,当从连接池取出的连接断开的时候,database/sql会自动尝试重连10次。仍然无法重连的情况下会自动从连接池再获取一个或者新建另外一个。

连接池配置配置连接池有两个的方法:

  • db.SetMaxOpenConns(n int) 设置打开数据库的最大连接数。包含正在使用的连接和连接池的连接。如果你的函数调用需要申请一个连接,并且连接池已经没有了连接或者连接数达到了最大连接数。此时的函数调用将会被block,直到有可用的连接才会返回。设置这个值可以避免并发太高导致连接mysql出现too many connections的错误。该函数的默认设置是0,表示无限制。
  • db.SetMaxIdleConns(n int) 设置连接池中的保持连接的最大连接数。默认也是0,表示连接池不会保持释放会连接池中的连接的连接状态:即当连接释放回到连接池的时候,连接将会被关闭。这会导致连接再连接池中频繁的关闭和创建。

对于连接池的使用依赖于你是如何配置连接池,如果使用不当会导致下面问题:

  • 大量的连接空闲,导致额外的工作和延迟。
  • 连接数据库的连接过多导致错误。
  • 连接阻塞。
  • 连接池有超过十个或者更多的死连接,限制就是10次重连。

数据库标准接口里面有3个方法用于设置连接池的属性: SetConnMaxLifetime, SetMaxIdleConns, SetMaxOpenConns

  • SetConnMaxLifetime: 设置一个连接的最长生命周期,因为数据库本身对连接有一个超时时间的设置,如果超时时间到了数据库会单方面断掉连接,此时再用连接池内的连接进行访问就会出错, 因此这个值往往要小于数据库本身的连接超时时间
  • SetMaxIdleConns: 连接池里面允许Idel的最大连接数, 这些Idel的连接 就是并发时可以同时获取的连接,也是用完后放回池里面的互用的连接, 从而提升性能。
  • SetMaxOpenConns: 设置最大打开的连接数,默认值为0表示不限制。控制应用于数据库建立连接的数量,避免过多连接压垮数据库。

项目结构

.
+--- Go.mod
+--- go.sum
+--- main.go
+--- pool
|   +--- sql-pool.go

代码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)
	}
}

可以通过工具ab测试连接池性能,用法见最下方注。

2.mysql-gorm 建立连接池

其实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
)

3.连接池相较于单个client

4.通用连接池

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}

参考

  • Apache Bench安装与使用
  • golang中mysql连接池使用
  • Golang Mysql笔记(一)--- 连接与连接池
  • golang 数据库连接池

 到此这篇关于golang mysql的连接池的具体使用的文章就介绍到这了,更多相关golang mysql连接池内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

您可能感兴趣的文档:

--结束END--

本文标题: golang mysql的连接池的具体使用

本文链接: https://www.lsjlt.com/news/196862.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • golang mysql的连接池的具体使用
    目录1.mysql-通过sql建立连接池2.mysql-gorm 建立连接池3.连接池相较于单个client4.通用连接池参考1.mysql-通过sql建立连接池 连接池用sql.Open函数创建连接池,可是此时只是初始...
    99+
    2023-02-21
    golangmysql连接池 golang连接池
  • golangmysql的连接池的具体使用
    目录1.mysql-通过sql建立连接池2.mysql-gorm 建立连接池3.连接池相较于单个client4.通用连接池参考1.mysql-通过sql建立连接池 连接池用sql.O...
    99+
    2023-02-21
    golang mysql连接池 golang 连接池
  • golang mysql的连接池如何使用
    本文小编为大家详细介绍“golang mysql的连接池如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“golang mysql的连接池如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知...
    99+
    2023-07-05
  • MySQL内外连接的具体使用
    目录内连接外连接左外连接右外连接简单案例MySQL内外连接 表的连接分为内连接和外连接。 内连接 内连接 内连接的SQL如下: SELECT ... FROM t1 INNE...
    99+
    2023-01-28
    MySQL内外连接
  • MySQL表内连和外连的具体使用
    目录一. 内连接二. 外连接1. 左外连接2. 右外连接一. 内连接 利用where子句对两种表形成的笛卡尔积进行筛选,其实就是内连接的一种方式另一种方式是inner join select 字段 f...
    99+
    2023-10-18
    MySQL表内连 MySQL表外连
  • mysql怎么使用连接池
    mysql使用连接池的示例:手动配置连接池。    public void demo1(){       &n...
    99+
    2024-04-02
  • Golang开发之接口的具体使用详解
    目录Golang的接口是什么什么情况下要用接口实战案例多态的例子定义通用方法的例子松耦合的例子实现插件化架构的例子Golang的接口是什么 在 Golang 中,接口是一种类型,它是...
    99+
    2023-05-14
    Golang接口使用 Golang接口 Go 接口
  • Golang中Model的具体使用
    目录导语使用之前的准备开始使用发布版本引用自己封装的包修改版本导语 我们都知道在Golang中我们一般都是设置GOPATH目录,这个目录主要存放我们的第三方包,这个方式一直不是很方便...
    99+
    2023-05-14
    Golang Model使用 Golang Model
  • golang中mysql数据库连接池的示例分析
    这篇文章主要介绍golang中mysql数据库连接池的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!golang的优点golang是一种编译语言,可以将代码编译为机器代码,编译后的二进制文件可以直接部署到目标...
    99+
    2023-06-15
  • golang 实用库gotable的具体使用
    目录一 背景二 库简介三 代码3.1 创建表格3.2 增加row3.3 增加column3.4 打印表格3.5 边框操作3.6 输出json四 测试4.1 创建表格4.2 输出jso...
    99+
    2024-04-02
  • 如何使用 PHP 设置 MySQL 连接池?
    使用 php 设置 mysql 连接池,可以提高性能和可伸缩性。步骤包括:1. 安装 mysqli 扩展;2. 创建连接池类;3. 设置连接池配置;4. 创建连接池实例;5. 获取和释放...
    99+
    2024-05-13
    mysql 连接池
  • Golang类型断言的具体使用
    目录一,如何检测和转换接口变量的类型二,类型判断:type-switch一,如何检测和转换接口变量的类型 在Go语言的interface中可以是任何类型,所以Go给出了类型断言来判断...
    99+
    2023-03-08
    Golang 类型断言
  • GoLang之gobuild命令的具体使用
    目录1.go build命令2.手动案例2.1新建文件2.2配置2.3go mod init2.4go get -u github.com/jinzhu/configor2.5go ...
    99+
    2024-04-02
  • python3 flask 使用连接池
    在真实的线上环境连接数据库一般都是要使用连接池的,连接池统一管理数据库连接,可以提高应用性能。python数据库连接池可以使用dbutils和PySQLPool但是这两个库似乎都只支持python2不支持python3,最后折腾了半天,P...
    99+
    2023-01-31
    连接池 flask
  • SpringBoot整合Tomcat连接池的使用
    连接池大小及性能选项 maxActive:最主要参数,配置连接池同时能维持的最大连接数,如果客户端理论上需要100个连接,则这个值设为100。 maxIdle:如...
    99+
    2024-04-02
  • Hibernate如何使用C3P0的连接池
    这篇文章主要介绍“Hibernate如何使用C3P0的连接池”,在日常操作中,相信很多人在Hibernate如何使用C3P0的连接池问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Hibernate如何使用C3...
    99+
    2023-06-03
  • java的mysql连接池怎么写
    利用java编写mysql连接池的方法具体内容如下:public class ConnecionPool {private int size;List connections = new ArrayList();public Conneci...
    99+
    2024-04-02
  • 怎么添加mysql连接池的最大连接数
    添加mysql连接池的最大连接数的设置方法:在MYSQL安装目录,找到配置文件 my.ini或my.cnf,打开配置文件,查找max_connections=100 修改为 max_connections=1000,保存,重启MYSQL服务...
    99+
    2024-04-02
  • jsp怎么使用mysql数据库连接池
    jsp使用mysql数据库连接池的方法在conf目录中打开context.xml文件,并在文件写如下代码;Web-INF/web.xml然后打开web.xml文件,在文件写入代码;GuestBookjdbc/ConnectionPoolja...
    99+
    2024-04-02
  • python怎么使用mysql数据库连接池
    python使用mysql数据库连接池的方法:安装数据库连接池模块DBUtils。pip3 install DBUtilsDBUtils是一套Python数据库连接池包,并允许对非线程安全的数据库接口进行线程安全包装。下...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作