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