背景:
在开发过程中遇到一个瓶颈那就是,数据库的连接池设置,有两个需求第一个就是大量用户同时并发操作数据库的时候,会出现连接超时问题。其次就是用户少量的时候如何实现快速的实现数据的相关操作:针对这两个问题,我们需要进行相关的数据库的配置。
首先我们采用的是Go语言开发,然后使用的就是Gorm包进行相关的数据库操作。
1. Grom相关的学习文档如下:
http://gorm.book.jasperxu.com/
https://gorm.io/docs/generic_interface.html
2. 连接池的原理参考博客:
3. 针对背景中遇到的问题,我们进行相关的处理:
1) 针对大量用户并发操作数据库出现连接超时问题:
gorm底层是根据sql.DB实现的,而sql.DB里面提供了相关的配置函数:
SetMaxOpenConns()表示最大的连接数,这个我们不设置默认就是不限制,可以无限创建连接,问题就在数据库本身有瓶颈,无限创建,会损耗性能。所以我们要根据我们自己的数据库瓶颈情况来进行相关的设置。当出现连接数超出了我们设定的数量时候,后面的用户等待超时时间之前,有连接释放就会自动获得操作的权限,否则返回连接超时。(每个公司的使用情况不同,所以根据情况自己设定,个人建议不要采用默认无限制创建连接)
2)针对少量用户快速实现相关数据库操作的问题:
gorm底层是根据sql.DB实现的,而sql.DB里面提供了相关的配置函数:
SetMaxIdleConns()表示设置最大的可空闲连接数,该函数的作用就是保持等待连接操作状态的连接数,这个主要就是避免操作过程中频繁的获取连接,释放连接。默认情况下会保持的连接数量为2.就是说会有两个连接一直保持,不释放,等待需要使用的用户使用。
3)一般情况上面的两个函数是一起使用的,而且最大连接数的设置,必须要大于最大可空闲连接数。
实例:我们下面以一个Gorm的实例进行相关的使用说明:
第一步: 我们要采用配置文件的方式进行相关的测试,配置文件名称:setings.yml。内容如下:
datasource:
maxConn: 200
maxOpen: 200
第二步:相关的viper获取配置文件信息,具体的细节可以参考我之前的相关博客:
type Database struct {
MaxConn int
MaxOpen int
}
var DatabaseConfig = new(Database) //设置全局的引用型指针变量
func GetConfig() *Database {
viper.SetConfigFile("conf/settings.yml")
content, err := ioutil.ReadFile("conf/settings.yml")
if err != nil {
fmt.Println("ioutil获取配置文件失败!")
}
err = viper.ReadConfig(strings.NewReader(os.ExpandEnv(string(content))))
if err != nil {
fmt.Println("viperhuoqu 配置文件失败!")
}
cfgDatabase := viper.Sub("datasource")
DatabaseConfig = InitDatabase(cfgDatabase)
return DatabaseConfig
}
func InitDatabase(cfg *viper.Viper) *Database {
db := &Database{
MaxConn: cfg.GetInt("maxConn"),
MaxOpen: cfg.GetInt("maxOpen"),
}
return db
}
第三步: 主函数进行相关的测试:
var DB *gorm.DB
func main() {
//获得一个*grom.DB对象
DB, err := gorm.Open("mysql", "username:password@/database?charset=utf8&parseTime=True&loc=Local")
if err != nil {
fmt.Println("Gorm 异常:", err)
}
//根据*grom.DB对象获得*sql.DB的通用数据库接口
sqlDb := DB.DB()
defer sqlDb.Close()
database := GetConfig()
fmt.Println("maxConn: ", database.MaxConn)
fmt.Println("maxOpen: ", database.MaxOpen)
sqlDb.SetMaxIdleConns(database.MaxConn) //设置最大连接数
sqlDb.SetMaxOpenConns(database.MaxOpen) //设置最大的空闲连接数
data, _ := json.Marshal(sqlDb.Stats()) //获得当前的SQL配置情况
fmt.Println(string(data))
}
最后一步就是:测试验证:
GOROOT=D:\Go #gosetup
GOPATH=E:\Gopath;E:\Develop\gowork;E:\GITwork\ginWork #gosetup
D:\Go\bin\go.exe build -o C:\Users\gree\AppData\Local\Temp\___8go_build_main_go.exe E:\Develop\gowork\src\test\main.go #gosetup
C:\Users\gree\AppData\Local\Temp\___8go_build_main_go.exe #gosetup
maxConn: 200
maxOpen: 200
{"MaxOpenConnections":200,"OpenConnections":1,"InUse":0,"Idle":1,"WaitCount":0,"WaitDuration":0,"MaxIdleClosed":0,"MaxIdleTimeClosed":0,"MaxLifetimeClosed":0}
Process finished with exit code 0
二. 更新空值问题:
方法1 :当前遇到一个问题,那就是使用gorm的时候采用更新方式去更新数据,如果更新后的值为0,“”或者nil,就不会更新该字段,而是只更新非空的其他字段。
解决方式,采用map去更新要更新的数据,不需要采用struct结构体。
方法2: 采用save的方式,先进行take获取源数据,然后在save进行保存。
func Test2(t *testing.T) {
dsn := "root:****@tcp(127.0.0.1:3306)/Mytest?charset=utf8&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
var pro ProTransMapping
pro.ID = 1
db.Debug().Where("id = ?",pro.ID).Take(&pro)
pro.Manufacturer = ""
pro.DevicePro = ""
db.Save(&pro)
}