V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
purplecity
V2EX  ›  问与答

go 多个 goroutine 操作 mysql 出现数据混乱

  •  
  •   purplecity · 2019-08-17 11:49:52 +08:00 · 2264 次点击
    这是一个创建于 1929 天前的主题,其中的信息可能已经有所发展或是发生改变。

    用的 beego 的 orm 数据库连接数 10000 innodb

    用的是一个全局单例的 orm 对象

    起 200 个进程 每秒起 1 个 goroutine 去操作数据库 每个 goroutine 去操作 5 次读和 2 次更新 即每秒有 200 个 routine 总共处理 1000 次读和 400 次写的时候 持续 60s 最后发现数据库数据混乱不对

    存在部分协程重复插入 少插入 没更新等操作 重复插入可以添加唯一索引解决 没插入和没更新怎么搞呢

    但是单个 goroutine 是没问题的

    求大佬给点建议

    9 条回复    2019-08-17 14:54:10 +08:00
    blless
        1
    blless  
       2019-08-17 12:29:20 +08:00 via Android
    业务锁啊 一个进程就本机实现一个全局业务锁。多节点就搞个分布式锁。
    Maboroshii
        2
    Maboroshii  
       2019-08-17 13:26:28 +08:00
    应该是操作有问题。
    起 200 个进程 是 起 200 个 go routine 吧? 出问题的时候是否有错误,有没有打错误日志?
    还有一个问题是你的数据来源是什么? 来源数据是否并发安全? 或者 orm 对象是否并发安全?
    hhyvs111
        3
    hhyvs111  
       2019-08-17 14:06:25 +08:00
    协程起来的时候是不是传的局部变量?还是传递的指针?如果传指针可能数据会被覆盖。
    liprais
        4
    liprais  
       2019-08-17 14:07:57 +08:00 via iPhone
    隔离级别了解一下
    keepeye
        5
    keepeye  
       2019-08-17 14:08:34 +08:00
    没有代码,无法给建议
    purplecity
        6
    purplecity  
    OP
       2019-08-17 14:36:52 +08:00
    具体程序
    ```go
    func init() {

    _ = orm.RegisterDataBase("default", "mysql",
    fmt.Sprintf("%s:%s@tcp(%s:%v)/%s?charset=utf8&allowNativePasswords=true",
    CommonConf.MysqlUserName, CommonConf.MysqlPassWord, CommonConf.MysqlIP, CommonConf.MysqlPort, CommonConf.MysqlDefaultDatabase))
    //注册模型
    orm.RegisterModel(new(AdminUsers),new(Realtrade))
    //自动创建表 参数二为是否 drop 然后创建表 参数三是否打印创建表过程
    orm.RunSyncdb("default",false,true)
    }

    var hpOrm orm.Ormer

    func getOrm() orm.Ormer {
    if hpOrm == nil {
    hpOrm = orm.NewOrm()
    }
    return hpOrm
    }

    func UpdateByCond(table string,cond,updateMap map[string]interface{}) {
    o := getOrm()
    qs := o.QueryTable(table)
    for key,value := range cond {
    qs = qs.Filter(key,value)
    }
    qs.Update(orm.Params(updateMap))
    }

    func GetOneRecord(table string,cond map[string]interface{},resultStruct interface{}) {
    o := getOrm()
    qs := o.QueryTable(table)
    for key,value := range cond {
    qs = qs.Filter(key,value)
    }
    qs.One(resultStruct)
    }

    func GetAllRecord(table string,cond map[string]interface{},resultStruct interface{}) {
    o := getOrm()
    qs := o.QueryTable(table)
    for key,value := range cond {
    qs = qs.Filter(key,value)
    }
    qs.All(resultStruct)
    }
    ```
    然后有个进程 A 每隔 1s 会去查库 查到了所需的 B 类型数据 有多少条就起多少个协程去用 UpdateByCond 和 GetOneRecord GetAllRecord 这些读取和更新操作。 模拟多个客户端我起了 200 个进程 这 200 个进程会在一分钟内每秒插入一条不同的 B 类型数据。所以 A 会每秒起 200 个 goroutine 去更新和读取操作。。。 比较挫。。用的是一个单利对象还没去看 beego orm 源码。。。 重复写和少写没更新都有。 别说 200 个进程了 10 个进程都会有出错。。
    purplecity
        7
    purplecity  
    OP
       2019-08-17 14:46:48 +08:00
    @hhyvs111 传的是变量没问题

    for _,x := range tidList {
    go func(m map[string]interface{}) {
    //对 m 进行操作
    }(x)
    purplecity
        8
    purplecity  
    OP
       2019-08-17 14:47:22 +08:00
    @keepeye 大佬代码在你下面一层。多谢
    purplecity
        9
    purplecity  
    OP
       2019-08-17 14:54:10 +08:00
    @Maboroshii 在下面具体说明了下 数据来源是数据库的数据是每秒都会去查库的 不过确实数据库操作的结果没打日志
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3608 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 04:35 · PVG 12:35 · LAX 20:35 · JFK 23:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.