Golang根據(jù)指定的兩個(gè)字段,批量刪除數(shù)據(jù)庫中的相關(guān)記錄

表格數(shù)據(jù)

app_id 參數(shù)名稱 參數(shù)值 參數(shù)值名稱
100074 qwe12345 mao11 超超1
100074 ssss mao3 超超1
100074 qwe12 ma01 超超2
100074 www mao3 超超3
100074 www mao4 超超4
100036 qwe12345 1233 123
100036 ssss mao3 123
100036 qwe12 100036 100036
100036 www www1 dd

對應(yīng)結(jié)構(gòu)體

type appEvents struct {
    ID          int32  `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`  // 主鍵
    AppID       string `gorm:"column:app_id;not null" json:"app_id"`               // 應(yīng)用id
    Params      string `gorm:"column:params;not null" json:"params"`               // 參數(shù)名稱
    ParamsValue string `gorm:"column:params_value;not null" json:"params_value"`   // 參數(shù)值
    ParamsLabel string `gorm:"column:params_label;not null" json:"params_label"`   // 參數(shù)值名稱
    Creator     int32  `gorm:"column:creator;not null" json:"creator"`             // 創(chuàng)建人id
    CreatedAt   int64  `gorm:"column:created_at;autoCreateTime" json:"created_at"` // 創(chuàng)建時(shí)間
    UpdatedAt   int64  `gorm:"column:updated_at;autoUpdateTime" json:"updated_at"` // 更新時(shí)間
}

錯(cuò)誤示例

appEventsIDStr := make([]string, 0, len(appEvents))
appEventsParams := make([]string, 0, len(appEvents))
for _, event := range appEvents {
    appEventsIDStr = append(appEventsIDStr, event.AppID)
    appEventsParams = append(appEventsParams, event.Params)
}
_, err = dao.WithContext(ctx).Where(dao.AppID.In(appEventsIDStr...), dao.Params.In(appEventsParams...)).Delete()
if err != nil {
    return err
}

這段代碼的意圖是:直接將表格中的AppIDParams裝入分別appEventsIDStrappEventsParams

然后批量刪除那些其 AppID 值存在于 appEventsIDStr 且其 Params 值存在于 appEventsParams 的記錄。

這會造成的問題如下:

正常刪除了如下數(shù)據(jù):

app_id 參數(shù)名稱
100074 qwe12345

但同時(shí)也會誤刪其他app_id下名稱為 qwe12345 的數(shù)據(jù):

app_id 參數(shù)名稱
100036 qwe12345

只要是 appEventsIDStr 包含的應(yīng)用id 和 appEventsParams 中包含的參數(shù)名稱都會被全部刪除!

這顯然是不符合業(yè)務(wù)需求的:刪除指定app_id和參數(shù)名稱下的數(shù)據(jù)

正確邏輯

  1. 創(chuàng)建映射:為 appEvents 創(chuàng)建一個(gè)映射,其中鍵由 AppIDParams 組合而成。
  2. 從數(shù)據(jù)庫獲取數(shù)據(jù):查詢數(shù)據(jù)庫,獲取那些其 AppIDParams 在指定的列表中的數(shù)據(jù)。
  3. 收集要刪除的 IDs:根據(jù)先前創(chuàng)建的映射,篩選出數(shù)據(jù)庫中需要刪除的條目的 IDs。
  4. 刪除數(shù)據(jù)庫條目:基于篩選出來的 IDs,執(zhí)行數(shù)據(jù)庫中的刪除操作。

代碼實(shí)現(xiàn)

// 將 appEventsIDStr 和 appEventsParams 組合成 map的key ,value為空結(jié)構(gòu)體的map
    appEventsMap := make(map[string]struct{}, len(appEventsIDStr))
    for _, event := range appEvents {
        appEventsMap[event.AppID+"_"+event.Params] = struct{}{}
    }

    // 批量刪除舊數(shù)據(jù)
    dao := tx.CfgEventParamsValue
    find, err := dao.WithContext(ctx).Where(dao.AppID.In(appEventsIDStr...), dao.Params.In(appEventsParams...)).Find()
    if err != nil {
        return err
    }
    var ids []int32
    for _, value := range find {
        // 將數(shù)據(jù)庫中的數(shù)據(jù)組合成map的key
        // value.AppID + "_" + value.Params 為map的key
        // value.ParamsValue 為map的value
        _, exists := appEventsMap[value.AppID+"_"+value.Params]
        if exists {
            ids = append(ids, value.ID)
        }
    }
    _, err = dao.WithContext(ctx).Where(dao.ID.In(ids...)).Delete()
    if err != nil {
        return err
    }

代碼詳解

  1. 構(gòu)建appEventsMap映射:
appEventsMap := make(map[string]struct{}, len(appEventsIDStr))
for _, event := range appEvents {
    appEventsMap[event.AppID+"_"+event.Params] = struct{}{}
}

在這段代碼中,首先初始化了一個(gè)名為 appEventsMap 的映射,其鍵是字符串,值是空結(jié)構(gòu)體(struct{} 不占用任何額外的內(nèi)存空間)。接下來,遍歷每個(gè) appEvents 條目并構(gòu)造映射鍵,該鍵是 AppIDParams 的組合,并為每個(gè)鍵分配一個(gè)空結(jié)構(gòu)體值。目的: 將 appEvents 列表轉(zhuǎn)換為映射,以便后續(xù)可以快速檢查某個(gè)組合(AppIDParams)是否存在于 appEvents 中。

  1. 查詢出要刪除的舊數(shù)據(jù):
appEventsIDStr := make([]string, 0, len(appEvents))
appEventsParams := make([]string, 0, len(appEvents))
for _, event := range appEvents {
    appEventsIDStr = append(appEventsIDStr, event.AppID)
    appEventsParams = append(appEventsParams, event.Params)
}

dao := tx.CfgEventParamsValue
find, err := dao.WithContext(ctx).Where(dao.AppID.In(appEventsIDStr...), dao.Params.In(appEventsParams...)).Find()
if err != nil {
    return err
}

使用 dao 查詢數(shù)據(jù)庫中的數(shù)據(jù)。此查詢的條件是 AppID 必須在 appEventsIDStr 中,Params 必須在 appEventsParams 中。

  1. 篩選要刪除的數(shù)據(jù)ID:
var ids []int32
for _, value := range find {
    _, exists := appEventsMap[value.AppID+"_"+value.Params]
    if exists {
        ids = append(ids, value.ID)
    }
}

在這個(gè)循環(huán)中,您檢查從數(shù)據(jù)庫查詢返回的每個(gè)條目是否存在于之前創(chuàng)建的 appEventsMap 中。如果存在,那么該條目的 ID 被添加到要刪除的ID列表中。

  1. 執(zhí)行刪除操作:
_, err = dao.WithContext(ctx).Where(dao.ID.In(ids...)).Delete()
if err != nil {
    return err
}

最后,執(zhí)行實(shí)際的刪除操作。您通過在ids列表中指定的ID來刪除所有條目。

綜合分析: 該代碼的主要目的是從數(shù)據(jù)庫中刪除特定的舊數(shù)據(jù)。這些數(shù)據(jù)由其AppIDParams確定,并在appEvents列表中給出。首先,代碼將這個(gè)列表轉(zhuǎn)換為一個(gè)映射,以便可以快速檢查一個(gè)給定的AppIDParams組合是否存在。然后,代碼查詢與這些AppIDParams組合匹配的所有數(shù)據(jù)庫條目,并刪除這些條目。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容