iris 数据库配置及连接方法封装
上一节讲完项目结构 & 生成数据表映射之后,接下来就是项目连接数据库操作数据库的代码封装:
连接数据库配置
数据库配置的主要目的就是为了把 Golang 链接数据库链接
"[User]:[Pwd]@tcp([Host]:[Port])/[DbName]?charset=[DbCharset]"
中的各项参数,变成结构体可标准配置
。比如:
type DbConf struct {
Host string
Port int
User string
Pwd string
DbName string
DbCharset string
}
工业项目一般都涉及多人开发,开发维护的时候为了统一管理。开发组内都会有自己的代码标准,所以这也是项目需要这配置那配置的配置化
原因
真正链接数据库的时候,使用fmt
格式化输出函数,就可以轻易获得链接数据库链接
const DriverName = "mysql"
var MasterDbConf DbConf = DbConf{
Host : "127.0.0.1",
Port : 3306,
User : "root",
Pwd : "",
DbName : "superstar",
DbCharset: "utf8",
}
conf := MasterDbConf
driverSource := fmt.Sprintf(
"%s:%s@tcp(%s:%d)/%s?charset=%s",
c.User, c.Pwd, c.Host, c.Port, c.DbName, c.DbCharset
)
fmt.Println(driverSource)
masterEngine, err := xorm.NewEngine(conf.DriverName, driverSource)
if err != nil {
log.Fatal("dbhelper.DbInstanceMaster err:", err)
return nil
}
配置可以不只一份,比如主从配置,读写分离。数据同步交给数据库主从同步,读取数据xorm.NewEngine
注意使用从库配置即可:
var SlaveDbConf DbConf = DbConf{
Host : "127.0.0.1",
Port : 3306,
User : "root",
Pwd : "",
DbName : "superstar",
DbCharset: "utf8",
}
到了实操阶段,我们在项目根目录下的conf
文件夹建db.go
文件:
conf/db.go
package conf
const DriverName = "mysql"
type DbConf struct {
Host string
Port int
User string
Pwd string
DbName string
}
var MasterDbConf DbConf = DbConf{
Host : "127.0.0.1",
Port : 3306,
User : "root",
Pwd : "",
DbName : "superstar",
}
var SlaveDbConf DbConf = DbConf{
Host : "127.0.0.1",
Port : 3306,
User : "root",
Pwd : "",
DbName : "superstar",
}
连接数据库方法封装
封装好数据库配置之后,为了使链接数据库方法变得一致,有利于日后统一管理。于是把上面提及的数据库链接方式封装成函数,就能在需要连接数据库时建立新的数据库链接。方便调用:
package datasource
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"log"
"superstar/conf"
"sync"
"xorm.io/xorm"
)
func InstanceMaster() *xorm.Engine {
c := conf.MasterDbConf
driverSource := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?",
c.User, c.Pwd, c.Host, c.Port, c.DbName)
fmt.Println(driverSource)
masterEngine, err := xorm.NewEngine(conf.DriverName, driverSource)
if err != nil {
log.Fatal("dbhelper.DbInstanceMaster err:", err)
return nil
}
return masterEngine
}
但每次操作数据库是,都建立新的数据库链接。不仅浪费数据库连接池资源、还容易在并发高情况下造成无法链接数据库。
于是我们需要一个数据库链接对象masterEngine
,在链接数据库前,检查对象是否为空,不为空就复用数据库链接;为空则重新建立数据库链接:
func InstanceMaster() *xorm.Engine {
if masterEngine != nil {
return masterEngine
}
c := conf.MasterDbConf
driverSource := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8",
c.User, c.Pwd, c.Host, c.Port, c.DbName)
fmt.Println(driverSource)
masterEngine, err := xorm.NewEngine(conf.DriverName, driverSource)
if err != nil {
log.Fatal("dbhelper.DbInstanceMaster err:", err)
return nil
}
return masterEngine
}
并发情况下数据库链接
但这里还有一个问题:
if masterEngine != nil {
return masterEngine
}
如果一下子,进来 10 个请求。第 1 个请求的 masterEngine
没来得及生成,导致后面 9 个请求也需要重复实例化 masterEngine
这种情况也不合理。
为了避免这种情况,我们在实例化 masterEngine
时加锁:
if masterEngine != nil {
return masterEngine
}
lock.Lock()
defer lock.Unlock() 后解锁
协程情况下数据库链接
协程时,上面 10 个请求一起进来,每个都到 lock.Lock()
加锁挂起。等第 1 个请求解锁后,后面 9 个请求也逐个实例化 masterEngine
这种情况也不合理。
为了避免这种情况,我在再加锁之后再次 判断 masterEngine
是否已存在:
if masterEngine != nil {
return masterEngine
}
lock.Lock()
defer lock.Unlock()
// 协程时,上面十个一起进来,每个都到 lock.Lock() 加锁挂起。这里避免 个加锁然后创建实例后,每个协程都创建实例
if masterEngine != nil {
return masterEngine
}
到了实操阶段,我们在项目根目录下的datasource
文件夹建dbhelper.go
文件:
datasource/dbhelper.go
package datasource
import (
"fmt"
_ "github.com/go-sql-driver/mysql"
"log"
"superstar/conf"
"sync"
"xorm.io/xorm"
)
// 数据库单例 dbhelper.go
var (
masterEngine *xorm.Engine
slaveEngine *xorm.Engine
lock sync.Mutex
)
func InstanceMaster() *xorm.Engine {
if masterEngine != nil {
return masterEngine
}
lock.Lock()
defer lock.Unlock()
if masterEngine != nil {
return masterEngine
}
c := conf.MasterDbConf
driverSource := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8",
c.User, c.Pwd, c.Host, c.Port, c.DbName)
fmt.Println(driverSource)
masterEngine, err := xorm.NewEngine(conf.DriverName, driverSource)
if err != nil {
log.Fatal("dbhelper.DbInstanceMaster err:", err)
return nil
}
// DEBUG 模式,打印全部sql, 帮助对比 orm 与 sql 执行对照关系
masterEngine.ShowSQL(false)
masterEngine.SetTZLocation(conf.SysTimeLocation)
return masterEngine
}
相关文章
Golang中的错误处理:使用context包处理请求超时错误
2023-08-07
请求
错误
超时
SQL数据库触发器语法详解 (sql数据库触发器语法)
2023-08-06
数据库
语法
触发器
快速简单的删除Oracle数据库字段方法 (删除oracl数据库字段)
2023-08-06
数据库
字段
删除
如何打开社工数据库bak文件 (社工数据库bak怎么打开)
2023-08-06
数据库
打开
社工
实现数据库按拼音排序的方法和技巧 (数据库按拼音排序)
2023-08-06
数据库
排序
按拼音
探究Sybase数据库的性能和功能特点 (sybase数据库怎么样)
2023-08-06
数据库
性能
探究
SQL Server 如何成功建立自己的数据库? (sql server 建立数据库)
2023-08-06
数据库
自己的
建立
如何在Oracle中查看数据库触发器? (oracle查看数据库触发器)
2023-08-06
数据库
查看
触发器
数据库表数据量千万级,对性能影响有多大? (数据库表千万级数据量多吗)
2023-08-06
数据库
级数
有多大
如何使用Oracle按时间导出表数据库? (oracle按时间导出表数据库)
2023-08-06
数据库
导出
如何使用
数据库存储:帖子长期保存,信息永不丢失 (帖子存数据库)
2023-08-06
数据库
丢失
帖子
小米六数据库:全方位数据保障和优化方案 (小米六数据库)
2023-08-05
数据库
优化
小米
简易教程:使用dbe数据库实现数据连接 (dbe数据库 数据连接)
2023-08-05
数据
数据库
连接
Oracle实现多个数据库链接的简便方法 (oracle链接多个数据库)
2023-08-05
数据库
多个
链接
数据库索引:用哪种方法建立? (数据库索引用什么建的)
2023-08-05
索引
数据库
哪种
实现高效缓存同步:Redis数据库技巧大全 (redis 数据库缓存同步)
2023-08-05
数据库
缓存
同步
如何利用数据库实现高效的模糊匹配查询? (数据库实现模糊查询)
2023-08-05
查询
数据库
模糊
数据库有哪些安装方式和位置? (数据库是装在什么上)
2023-08-05
数据库
位置
装在
Lactmed数据库:妈妈们必备的喂养指南 (lactmed 数据库)
2023-08-05
数据库
必备
喂养
数据库设计中的主属性定义及作用 (数据库主属性是什么)
2023-08-05
数据库
定义
属性