前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang对数据库操作--高并发与线程安全

Golang对数据库操作--高并发与线程安全

原创
作者头像
用户2825890
修改2020-12-28 11:44:44
3.3K0
修改2020-12-28 11:44:44
举报
文章被收录于专栏:点滴随笔

前些日子为了给java组同事提供直播端的商品详情接口,这些接口原本是由PHP开发组提供的,但由于直播并发压力问题,改由Golang来提供。

在由go开发接口过程中,发现在高并发下出现数据错乱--用A商品的ID查到B商品的详情,即线程安全问题,这主要是由数据查询构造器引起的。在低并发测环境并不会复现线程安全引起的数据错乱

一开始,数据库操作对像包括了连接器和查询器,只要实例化一个服务即实例化一个数据库操作对像提供数据库操作服务

这样设计,好处是共享链接,减少打开连接句柄的开销,提升数据库操作的并发能力和服务器的连接开销。但缺点是共享的链接是在同一个数据库操作对像中,在构造查询器中涉及查询语句的构建,这样,就会在多个商品高并发查询时,引起查询语句在多线程下获得本不是所属商品的查询语句。

改良的办法就是将数据库查询构造器从数据库操作对像中分离出来,并引用同一个连接器对像,这里一定要使用指针,不然就会发起多个数据库连接。

附上数据库操作对像

DB.go

代码语言:go
复制
...
//创建连接器
type DbConnection struct{
    DB *sql.DB
}
//构建查询器
type DbQuery struct {
    Wher string //[]map[string]string
    Joinn string
    Wherestring string
    order string
    limit string
    alias string
    table string
    group string
    update string
    save string
    field string
    DB *sql.DB
    Rows interface{}
    Row interface{}
    sync.RWMutex
}
//构建连接
func (DbConnection *DbConnection) Connt (cnt map[string]string) {
	dsn := fmt.Sprintf("%s:%s@%s(%s:%s)/%s",cnt["username"],cnt["password"],cnt["network"],cnt["server"],cnt["port"],cnt["database"])
    db,err := sql.Open("mysql",dsn)
    if err != nil{
        fmt.Printf("Open mysql failed,err:%v\n",err)
    }
    db.SetConnMaxLifetime(100*time.Second)
    db.SetMaxOpenConns(500)
    db.SetMaxIdleConns(16)
    DbConnection.DB = db
}
...

使用:

server.go

代码语言:javascript
复制
...
	flag.Parse()

	s := server.NewServer()
	addRegistryPlugin(s)

	dbcnt:=make(map[string]string)
	dbcnt["username"] = "dbname"
	dbcnt["password"] = "*******"
	dbcnt["port"] = "3306"
	dbcnt["database"] = "mall"
	dbcnt["network"]  = "tcp"
	dbcnt["server"]   = "127.0.0.1"
	// var Db *sql.DB
	d:=new(db.DbConnection)
	d.Connt(dbcnt)
	goodsmodel := goods.Goods{*d}//注册对像时传递数据库连接对像指针
	s.RegisterName("Goods", &goodsmodel, "")
	s.Serve("tcp", *addr)
...

service.go

共享数据库连接器,但每次查询都构建一个新的查询器实例 d:=new(db.DbQuery),完美解决高并发下对数据库查询的线程安全问题

代码语言:javascript
复制
...
//conn *db.DbConnection 共享连接
func getShopGoodBaseInfo(conn *db.DbConnection,goodsId int) *map[string]string {
    //获取商品基础信息
    field := `goods_base `
    d:=new(db.DbQuery)
    d.Builder(conn)
    d.Table("goods")
    d.Field(field)
    where := fmt.Sprintf("goods_id = %d", goodsId)
    d.Where(where)
    rows := d.Find()
    goodsBaseInfo :=d.GetRow(rows)
    return &goodsBaseInfo
}
...

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档