github.com/team-ide/go-dialect@v1.9.20/worker/task_sync.go (about) 1 package worker 2 3 import ( 4 "database/sql" 5 "errors" 6 "fmt" 7 "github.com/team-ide/go-dialect/dialect" 8 "strings" 9 ) 10 11 func NewTaskSync(sourceDB *sql.DB, sourceDialect dialect.Dialect, targetDb *sql.DB, targetDialect dialect.Dialect, newDb func(owner *TaskSyncOwner) (db *sql.DB, err error), taskSyncParam *TaskSyncParam) (res *taskSync) { 12 task := &Task{ 13 dia: sourceDialect, 14 db: sourceDB, 15 onProgress: taskSyncParam.OnProgress, 16 } 17 res = &taskSync{ 18 Task: task, 19 targetDialect: targetDialect, 20 targetDb: targetDb, 21 TaskSyncParam: taskSyncParam, 22 newDb: newDb, 23 } 24 task.do = res.do 25 return 26 } 27 28 type TaskSyncParam struct { 29 Owners []*TaskSyncOwner `json:"owners"` 30 31 BatchNumber int `json:"batchNumber"` 32 SyncStruct bool `json:"syncStruct"` 33 SyncData bool `json:"syncData"` 34 ErrorContinue bool `json:"errorContinue"` 35 OwnerCreateIfNotExist bool `json:"ownerCreateIfNotExist"` 36 37 FormatIndexName func(ownerName string, tableName string, index *dialect.IndexModel) string `json:"-"` 38 OnProgress func(progress *TaskProgress) `json:"-"` 39 } 40 41 type TaskSyncOwner struct { 42 SourceName string `json:"sourceName"` 43 TargetName string `json:"targetName"` 44 SkipTableNames []string `json:"skipTableNames"` 45 Tables []*TaskSyncTable `json:"tables"` 46 Username string `json:"username"` 47 Password string `json:"password"` 48 } 49 50 type TaskSyncTable struct { 51 SourceName string `json:"sourceName"` 52 TargetName string `json:"targetName"` 53 Columns []*TaskSyncColumn `json:"columns"` 54 } 55 56 type TaskSyncColumn struct { 57 SourceName string `json:"sourceName"` 58 TargetName string `json:"targetName"` 59 } 60 61 type taskSync struct { 62 *Task 63 *TaskSyncParam 64 targetDialect dialect.Dialect 65 targetDb *sql.DB 66 newDb func(owner *TaskSyncOwner) (db *sql.DB, err error) 67 } 68 69 func (this_ *taskSync) do() (err error) { 70 71 defer func() { 72 if e := recover(); e != nil { 73 err = errors.New(fmt.Sprint(e)) 74 } 75 }() 76 77 owners := this_.Owners 78 if len(owners) == 0 { 79 return 80 } 81 this_.countIncr(&this_.OwnerCount, len(owners)) 82 for _, owner := range owners { 83 var success bool 84 success, err = this_.syncOwner(owner) 85 if success { 86 this_.countIncr(&this_.OwnerSuccessCount, 1) 87 } else { 88 this_.countIncr(&this_.OwnerErrorCount, 1) 89 } 90 if err != nil { 91 return 92 } 93 } 94 95 return 96 } 97 98 func (this_ *taskSync) syncOwner(owner *TaskSyncOwner) (success bool, err error) { 99 progress := &TaskProgress{ 100 Title: "同步[" + owner.SourceName + "]", 101 } 102 defer func() { 103 if e := recover(); e != nil { 104 err = errors.New(fmt.Sprint(e)) 105 } 106 if err != nil { 107 progress.Error = err.Error() 108 if progress.OnError != nil { 109 progress.OnError(err) 110 } 111 } 112 113 if this_.ErrorContinue { 114 err = nil 115 } 116 }() 117 118 this_.addProgress(progress) 119 120 ownerOne, err := OwnerSelect(this_.db, this_.dia, this_.Param, owner.SourceName) 121 if err != nil { 122 //fmt.Println("task sync syncOwner OwnerSelect owner:", owner.SourceName, " error:", err.Error()) 123 return 124 } 125 if ownerOne == nil { 126 err = errors.New("source db owner [" + owner.SourceName + "] is not exist") 127 return 128 } 129 130 tables := owner.Tables 131 132 if len(tables) == 0 { 133 var list []*dialect.TableModel 134 list, err = TablesSelect(this_.db, this_.dia, this_.Param, owner.SourceName) 135 if err != nil { 136 //fmt.Println("task sync syncOwner TablesSelect owner:", owner.SourceName, " error:", err.Error()) 137 return 138 } 139 progress.Infos = append(progress.Infos, fmt.Sprintf("owner[%s] table size[%d]", owner.SourceName, len(list))) 140 for _, one := range list { 141 tables = append(tables, &TaskSyncTable{ 142 SourceName: one.TableName, 143 }) 144 } 145 } 146 targetOwnerName := owner.TargetName 147 if targetOwnerName == "" { 148 targetOwnerName = owner.SourceName 149 } 150 151 targetOwnerOne, err := OwnerSelect(this_.targetDb, this_.targetDialect, this_.Param, targetOwnerName) 152 if err != nil { 153 return 154 } 155 if targetOwnerOne == nil { 156 if !this_.OwnerCreateIfNotExist { 157 err = errors.New("target db owner [" + targetOwnerName + "] is not exist") 158 return 159 } 160 this_.addProgress(&TaskProgress{ 161 Title: "同步[" + targetOwnerName + "] 不存在,创建", 162 }) 163 _, err = OwnerCreate(this_.targetDb, this_.targetDialect, this_.Param, &dialect.OwnerModel{ 164 OwnerName: targetOwnerName, 165 OwnerPassword: owner.Password, 166 OwnerCharacterSetName: "utf8mb4", 167 }) 168 if err != nil { 169 return 170 } 171 } 172 173 workDb, err := this_.newDb(owner) 174 if err != nil { 175 return 176 } 177 178 this_.countIncr(&this_.TableCount, len(tables)) 179 for _, table := range tables { 180 181 if len(owner.SkipTableNames) > 0 { 182 var skip bool 183 for _, skipTableName := range owner.SkipTableNames { 184 if strings.EqualFold(table.SourceName, skipTableName) { 185 skip = true 186 } 187 } 188 if skip { 189 this_.countIncr(&this_.TableSuccessCount, 1) 190 continue 191 } 192 } 193 194 var success_ bool 195 success_, err = this_.syncTable(workDb, owner.SourceName, table.SourceName, owner.TargetName, table.TargetName) 196 if success_ { 197 this_.countIncr(&this_.TableSuccessCount, 1) 198 } else { 199 this_.countIncr(&this_.TableErrorCount, 1) 200 } 201 if err != nil { 202 return 203 } 204 } 205 success = true 206 207 return 208 } 209 210 func (this_ *taskSync) syncTable(workDb *sql.DB, sourceOwnerName string, sourceTableName string, targetOwnerName string, targetTableName string) (success bool, err error) { 211 if targetOwnerName == "" { 212 targetOwnerName = sourceOwnerName 213 } 214 if targetTableName == "" { 215 targetTableName = sourceTableName 216 } 217 progress := &TaskProgress{ 218 Title: "同步[" + sourceOwnerName + "." + sourceTableName + "] 到 [" + targetOwnerName + "." + targetTableName + "]", 219 } 220 defer func() { 221 if e := recover(); e != nil { 222 err = errors.New(fmt.Sprint(e)) 223 } 224 if err != nil { 225 progress.Error = err.Error() 226 if progress.OnError != nil { 227 progress.OnError(err) 228 } 229 } 230 231 if this_.ErrorContinue { 232 err = nil 233 } 234 }() 235 236 this_.addProgress(progress) 237 238 newTableDetail, err := TableDetail(this_.db, this_.dia, this_.Param, sourceOwnerName, sourceTableName, false) 239 if err != nil { 240 return 241 } 242 if newTableDetail == nil { 243 err = errors.New("source db table [" + sourceOwnerName + "." + sourceTableName + "] is not exist") 244 return 245 } 246 oldTableDetail, err := TableDetail(this_.targetDb, this_.targetDialect, this_.Param, targetOwnerName, targetTableName, false) 247 if err != nil { 248 return 249 } 250 if oldTableDetail == nil { 251 oldTableDetail = &dialect.TableModel{} 252 } 253 oldTableDetail.OwnerName = targetOwnerName 254 oldTableDetail.TableName = targetTableName 255 if this_.SyncStruct { 256 err = this_.syncTableSyncStructure(workDb, newTableDetail, oldTableDetail) 257 if err != nil { 258 return 259 } 260 } 261 if this_.SyncData { 262 err = this_.syncTableSyncData(workDb, newTableDetail, oldTableDetail) 263 if err != nil { 264 return 265 } 266 } 267 success = true 268 return 269 } 270 271 func (this_ *taskSync) syncTableSyncStructure(workDb *sql.DB, newTableDetail *dialect.TableModel, oldTableDetail *dialect.TableModel) (err error) { 272 273 progress := &TaskProgress{ 274 Title: "同步表结构[" + newTableDetail.OwnerName + "." + newTableDetail.TableName + "] 到 [" + oldTableDetail.OwnerName + "." + oldTableDetail.TableName + "]", 275 } 276 defer func() { 277 if e := recover(); e != nil { 278 err = errors.New(fmt.Sprint(e)) 279 } 280 if err != nil { 281 progress.Error = err.Error() 282 if progress.OnError != nil { 283 progress.OnError(err) 284 } 285 } 286 287 if this_.ErrorContinue { 288 err = nil 289 } 290 }() 291 292 this_.addProgress(progress) 293 294 if this_.FormatIndexName != nil { 295 for _, index := range newTableDetail.IndexList { 296 index.IndexName = this_.FormatIndexName(oldTableDetail.OwnerName, oldTableDetail.TableName, index) 297 } 298 } 299 if len(oldTableDetail.ColumnList) == 0 { 300 newTableDetail.TableName = oldTableDetail.TableName 301 err = TableCreate(workDb, this_.targetDialect, this_.Param, oldTableDetail.OwnerName, newTableDetail) 302 if err != nil { 303 return 304 } 305 return 306 } else { 307 err = TableUpdate(workDb, this_.targetDialect, oldTableDetail, this_.dia, newTableDetail) 308 if err != nil { 309 return 310 } 311 } 312 return 313 } 314 315 func (this_ *taskSync) syncTableSyncData(workDb *sql.DB, newTableDetail *dialect.TableModel, oldTableDetail *dialect.TableModel) (err error) { 316 317 progress := &TaskProgress{ 318 Title: "同步表数据[" + newTableDetail.OwnerName + "." + newTableDetail.TableName + "] 到 [" + oldTableDetail.OwnerName + "." + oldTableDetail.TableName + "]", 319 } 320 defer func() { 321 if e := recover(); e != nil { 322 err = errors.New(fmt.Sprint(e)) 323 } 324 if err != nil { 325 progress.Error = err.Error() 326 if progress.OnError != nil { 327 progress.OnError(err) 328 } 329 } 330 331 if this_.ErrorContinue { 332 err = nil 333 } 334 }() 335 336 this_.addProgress(progress) 337 338 selectSqlInfo := "SELECT " 339 var columnNames []string 340 for _, one := range newTableDetail.ColumnList { 341 columnNames = append(columnNames, one.ColumnName) 342 } 343 selectSqlInfo += this_.dia.ColumnNamesPack(this_.Param, columnNames) 344 selectSqlInfo += " FROM " 345 selectSqlInfo += this_.dia.OwnerTablePack(this_.Param, newTableDetail.OwnerName, newTableDetail.TableName) 346 347 countSql, err := dialect.FormatCountSql(selectSqlInfo) 348 if err != nil { 349 return 350 } 351 totalCount, err := DoQueryCount(this_.db, countSql, nil) 352 if err != nil { 353 return 354 } 355 356 this_.countIncr(&this_.DataCount, totalCount) 357 batchNumber := this_.BatchNumber 358 if batchNumber <= 0 { 359 batchNumber = 100 360 } 361 var pageSize = batchNumber 362 var pageNo = 1 363 364 var dataList []map[string]interface{} 365 var columnList = newTableDetail.ColumnList 366 if len(oldTableDetail.ColumnList) > 0 { 367 columnList = oldTableDetail.ColumnList 368 } 369 for { 370 371 if this_.IsStop { 372 return 373 } 374 pageSql := this_.dia.PackPageSql(selectSqlInfo, pageSize, pageNo) 375 dataList, err = DoQuery(this_.db, pageSql, nil) 376 if err != nil { 377 return 378 } 379 pageNo += 1 380 dataListCount := len(dataList) 381 this_.countIncr(&this_.DataReadyCount, dataListCount) 382 if dataListCount == 0 { 383 break 384 } 385 var success bool 386 success, err = this_.insertDataList(workDb, dataList, oldTableDetail.OwnerName, oldTableDetail.TableName, columnList) 387 if success { 388 this_.countIncr(&this_.DataSuccessCount, dataListCount) 389 } else { 390 this_.countIncr(&this_.DataErrorCount, dataListCount) 391 } 392 if err != nil { 393 return 394 } 395 if dataListCount == 0 { 396 break 397 } 398 } 399 400 return 401 } 402 403 func (this_ *taskSync) insertDataList(workDb *sql.DB, dataList []map[string]interface{}, targetOwnerName string, targetTableName string, columnList []*dialect.ColumnModel) (success bool, err error) { 404 405 progress := &TaskProgress{ 406 Title: "插入数据[" + targetOwnerName + "." + targetTableName + "]", 407 } 408 defer func() { 409 if e := recover(); e != nil { 410 err = errors.New(fmt.Sprint(e)) 411 } 412 if err != nil { 413 progress.Error = err.Error() 414 if progress.OnError != nil { 415 progress.OnError(err) 416 } 417 } 418 419 if this_.ErrorContinue { 420 err = nil 421 } 422 }() 423 424 this_.addProgress(progress) 425 426 _, _, batchSqlList, batchValuesList, err := this_.targetDialect.DataListInsertSql(this_.Param, targetOwnerName, targetTableName, columnList, dataList) 427 if err != nil { 428 return 429 } 430 var errSql string 431 _, errSql, _, err = DoExecs(workDb, batchSqlList, batchValuesList) 432 if err != nil { 433 if errSql != "" { 434 err = errors.New("sql:" + errSql + " exec error," + err.Error()) 435 } 436 return 437 } 438 success = true 439 return 440 }