背景:

        在开发过程中遇到一个瓶颈那就是,数据库的连接池设置,有两个需求第一个就是大量用户同时并发操作数据库的时候,会出现连接超时问题。其次就是用户少量的时候如何实现快速的实现数据的相关操作:针对这两个问题,我们需要进行相关的数据库的配置。

首先我们采用的是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)
}