对mysql上的不同操作使用多个go例程

对mysql上的不同操作使用多个go例程,mysql,go,Mysql,Go,我有一段Go代码,包含3个不同的函数:insertIntoMysql、updateRowMysql和deleteRowmysql。我检查操作类型,并根据需要运行其中一个函数 我想把我的普通函数转换成go例程,以便能够处理更多的操作 但问题是: 如果我转换为goroutine,我将丢失操作序列 例如,插入操作比删除操作要频繁得多,当删除通道为空时,插入操作在插入通道中排队。我的代码可以在插入行之前尝试删除行(例如,插入行并在1秒后删除行) 关于如何确保我在mysql上的操作序列与接收到的操作序列相

我有一段Go代码,包含3个不同的函数:insertIntoMysql、updateRowMysql和deleteRowmysql。我检查操作类型,并根据需要运行其中一个函数


我想把我的普通函数转换成go例程,以便能够处理更多的操作

但问题是:
如果我转换为goroutine,我将丢失操作序列

例如,插入操作比删除操作要频繁得多,当删除通道为空时,插入操作在插入通道中排队。我的代码可以在插入行之前尝试删除行(例如,插入行并在1秒后删除行)

关于如何确保我在mysql上的操作序列与接收到的操作序列相同的想法

代码如下:


    go insertIntoMysql(insertChan, fields, db, config.DestinationTable)
    go updatefieldMysql(updateChan, fields, db, config.DestinationTable)
    go deleteFromMysql(deleteChan, fields, db, config.DestinationTable)


    for !opsDone {
        select {
        case op, open := <-mysqlChan:
            if !open {
                opsDone = true
                break
            }

            switch op.Operation {
            case "i":
                //fmt.Println("got insert operation")
                insertChan <- op
                break
            case "u":
                fmt.Println("got update operation")
                updateChan <- op
                break
            case "d":
                fmt.Println("got delete operation")
                deleteChan <- op
                break
            case "c":
                fmt.Println("got command operation")
                //no logic yet
                break
            }

            break
        }
    }
    close(done)
    close(insertChan)
    close(deleteChan)
    close(updateChan)

}

go insertIntoMysql(insertChan,字段,数据库,config.DestinationTable)
go updatefieldMysql(updateChan,fields,db,config.DestinationTable)
go deleteFromMysql(deleteChan,fields,db,config.DestinationTable)
对于opsDone{
挑选{

案例op,open:=据我所知,以下是解决问题的方法:

  • 调用Insert、Delete或Update as go例程,它们将并发运行并执行所有这些操作

  • 确保MySQL数据库中有行级锁定(我确信InnoDb提供了这一功能)

  • 对于删除和更新操作,请在删除和更新行之前进行isExist检查,以检查要更新/删除的行是否存在,这允许某种程度的控制

  • 您可以在通道中实现重试机制(最好使用抖动),以确保即使在插入操作之前执行删除操作,它也会失败存在检查,然后可以重试(在一秒或0.5秒或某些配置之后)这将确保在重试删除或更新操作之前已执行插入记录


  • 希望这有帮助。

    调用
    delete
    的人首先是如何知道该行的?从SQL的角度来看:如果未提交,则该行不存在。有东西调用您的代码以
    插入
    。您的代码应该仅在事务完成后返回。此时,调用方可以启动
    选择
    更新
    删除

    例如,在web服务器中:只有调用
    insert
    的客户端最初知道该记录的存在。其他客户端只有在运行
    select
    后才会知道该记录的存在。如果新记录是在
    insert
    插入该记录的事务中提交的,则
    select
    才会返回该记录。现在,它们会丢失该记录ght决定
    追加插入
    删除

    许多SQL数据库采用适当的方式,这将确保并发访问期间的数据完整性。因此,如果使用Go例程写入同一条记录,它们在数据库端将成为连续的(以任何给定的顺序)。并发读取仍然可能发生


    请注意,
    net/http
    已经为每个请求运行了Go例程。Go的大多数其他服务器前端也是如此。如果您正在编写一些完全不同的东西,比如自定义TCP侦听器,您可以为每个请求启动自己的Go例程。

    查看您的代码和问题/要求:按顺序执行原始go频道提供了数据。 保持同步并仍然启动多个go例程来处理数据,可以这样做:

    func processStatements(mysqlChan chan *instructions) {
        var wg sync.WaitGroup
        prevOp := "" // Previous operation
        for {
            op, open := <-mysqlChan
            if !open {
                break
            }
            if prevOp!=op.Operation {
                // Next operation type, unknown side effects on previous operations, 
                // wait for previous to finish before continuing
                wg.Wait()
            }
    
            switch op.Operation {
            case "i":
                wg.Add(1)
                go processInsert(op,wg)
                break
            case "u":
                wg.Add(1)
                go processUpdate(op,wg)
                break
            case "d":
                wg.Add(1)
                go processDelete(op,wg)
                break
            case "c":
                break
            }
            prevOp = op.Operation
        }
        // Previous go routines might still be running, wait till done
        wg.Wait()
        // Close any channels
    }
    
    func processInsert(c chan *sqlCall,wg *sync.WaitGroup) {
        defer wg.Done()
        // Do actual insert etc
    }
    
    func processStatements(mysqlChan*指令){
    var wg sync.WaitGroup
    prevOp:=“”//上一个操作
    为了{
    
    op,open:=“我想将我的普通函数转换为go例程”这在逻辑上是不可能的。goroutines和函数是绝对不同的。函数是要执行的代码单元。goroutine是一个调度概念。goroutines运行函数。函数不能“变成”goroutines。除此之外,在没有看到您正在使用的实际代码的情况下提供建议是不可能的。您是否会尝试这些TNX反馈,以了解此答案被否决的原因?我认为此答案将起作用,并且我可以提供完整的解决方案(如果问题要求相同)我的代码假设接收到的操作是正确的,但是我需要在使用mysql时保持操作顺序,同时使用不同的go Routines执行创建、更新和删除操作的路由是独立的,并且有单独的通道。您的逻辑是合理的,但是我有一个问题:在繁忙的数据库上,假设插入1000次按顺序进行是否最好如此快速地生成所有这些go例程?这实际上取决于数据库吞吐量和设置:您可能希望从一个连接池开始(您不希望与几乎任何数据库建立5k连接)。最终,数据库将按每页顺序执行,其中较小的页面设置有助于提高吞吐量(但也会降低开销,因为每页的记录数将较低)。使用许多go例程可以减少网络等待。您还可以限制可能要启动的例程数量,以防止OOM(并失去您的交易)