代码如下:
func (s *MonitorDiskService) SyncData(c *SyncConfig) (err error) {
data, err := s.getData(c, nil, nil)
if err != nil {
return err
}
diskInfo := table.GetMonitorDiskInfos(data, c.relation)
now := time.Now()
var disks []*model.MonitorDiskInfo
for _, info := range diskInfo {
info.CloudUUID = c.cloud.UUID
info.UpdateTime = now
if info.ID == "" {
continue
}
disks = append(disks, info)
}
q := query.Use(s.db.GetDb())
tx := q.Begin()
defer func() {
if recover() != nil || err != nil {
_ = tx.Rollback()
}
}()
vi := tx.MonitorDiskInfo
_, err = vi.WithContext(context.TODO()).Where(vi.CloudUUID.Eq(c.cloud.UUID)).Delete()
if err != nil {
return err
}
// 注意:现场有的云环境同步monitor_disk_info数据时delete后create数据会报主键冲突,其它monitor_disk_info正常同步,问题根因不明,只能将create换为save
for i := 0; true; i++ {
if (i+1)*configs.SyncCreateLimit >= len(data) {
err = vi.WithContext(context.TODO()).Save(disks[i*configs.SyncCreateLimit:]...)
if err != nil {
s.logger.Error(fmt.Sprintf("table monitor_disk_info create index from:%v to:%v of data failed,index,err:%v",i*configs.SyncCreateLimit,len(data),err))
return err
}
break
} else {
err = vi.WithContext(context.TODO()).Save(disks[i*configs.SyncCreateLimit : (i+1)*configs.SyncCreateLimit]...)
if err != nil {
s.logger.Error(fmt.Sprintf("table monitor_disk_info create index from:%v to:%v of data failed,index,err:%v",i*configs.SyncCreateLimit,(i+1)*configs.SyncCreateLimit,err))
return err
}
}
}
return tx.Commit()
}
代码业务逻辑为:
这是一段同步disks数据到数据库的代码,其中 disks为需要保存到表的数据,代码逻辑为:先delete表的数据,再分批次insert数据到表。
问题:
本地环境测试没有问题,数据正常同步保存。但是在客户环境,客户有两台环境A和B,其中A可以正常同步数据,B不行,会报错主键冲突的问题。
怀疑数据delete的时候没有成功,导致后面insert报错主键冲突,但是通过日志打断点方式,确认delete那里的err为空,不知道该怎么排查了。
背景:同步的这个服务是一个k8s微服务,只有一个pod,没有启用多副本。环境的mysql是3节点,1主2从