求一个Go的解决方案或思路

qq_22264283 2025-01-14 16:52:10

在数据库中,存放有A表,结构及数据如下,其中task的取值范围为1-4,i和j的值都是整数

Num    Th    Task    BZ
i    j    1    0
i    j    2    0
i    j    3    1
i    j    4    0

另外 还有一B表,结构及数据如下,其中task的取值范围为1-4,m和j的值都是整数

Tid    Th    Task
m    j    1
m    j    2
m    j    3
m    j    4

需求:用B表中的Th和Task两列的数组去匹配A表中bz为0的数据,要求返回匹配后的数据如下;同时将已经匹配后的A中的数据打上标记 1(表示 已匹配)或者直接将其删除也可以。
要求在高并发环境下,高效完成,同时保证结果正确,不能出现重复匹配的情况。
Num    Tid    Th    Task
i    m    j    1
i    m    j    2
i    m    j    3
i    m    j    4

求思路或方案,谢谢!

...全文
成就一亿技术人!
拼手气红包 15.00元
9542 2 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复

希望能帮到你

package main

import (
    "database/sql"
    "fmt"
    "log"
    "math/rand"
    "time"
)

// MatchAndUpdate 匹配 A 表和 B 表的数据,并更新 A 表中的 BZ 字段为 1(表示已匹配)。
// 在高并发环境下,通过事务、锁机制和重试机制确保数据一致性和高效性。
func MatchAndUpdate(db *sql.DB, batchSize int, maxRetries int, retryDelayRange [2]float64) ([]map[string]interface{}, error) {
    // 初始化随机数种子
    rand.Seed(time.Now().UnixNano())

    // 定义返回的匹配数据
    var matchedData []map[string]interface{}

    // 重试机制
    for retries := 0; retries < maxRetries; retries++ {
        // 开始事务
        tx, err := db.Begin()
        if err != nil {
            log.Printf("开始事务失败: %v", err)
            continue
        }

        // 查询匹配数据
        // 使用 JOIN 操作将 A 表和 B 表基于 Th 和 Task 列进行匹配
        // 只匹配 A 表中 BZ 为 0 的数据
        // 使用 FOR UPDATE 对匹配的行加锁,防止其他事务修改这些行
        query := `
            SELECT A.Num, B.Tid, A.Th, A.Task
            FROM A
            JOIN B ON A.Th = B.Th AND A.Task = B.Task
            WHERE A.BZ = 0
            LIMIT ?
            FOR UPDATE
        `
        rows, err := tx.Query(query, batchSize)
        if err != nil {
            log.Printf("查询匹配数据失败: %v", err)
            tx.Rollback()
            continue
        }

        // 解析查询结果
        for rows.Next() {
            var num, tid, th, task int
            if err := rows.Scan(&num, &tid, &th, &task); err != nil {
                log.Printf("解析查询结果失败: %v", err)
                tx.Rollback()
                return nil, err
            }
            matchedData = append(matchedData, map[string]interface{}{
                "Num":  num,
                "Tid":  tid,
                "Th":   th,
                "Task": task,
            })
        }
        rows.Close()

        if len(matchedData) == 0 {
            // 如果没有匹配的数据,提交事务并退出
            tx.Commit()
            log.Println("未找到匹配的数据,提交事务并退出。")
            return matchedData, nil
        }

        // 更新 A 表
        // 将 A 表中已匹配的数据的 BZ 字段更新为 1,表示已匹配
        // 使用 EXISTS 子查询确保只更新匹配的数据
        updateQuery := `
            UPDATE A
            SET BZ = 1
            WHERE BZ = 0
            AND EXISTS (
                SELECT 1
                FROM B
                WHERE A.Th = B.Th AND A.Task = B.Task
            )
            LIMIT ?
        `
        _, err = tx.Exec(updateQuery, batchSize)
        if err != nil {
            log.Printf("更新 A 表失败: %v", err)
            tx.Rollback()
            continue
        }

        // 提交事务
        if err := tx.Commit(); err != nil {
            log.Printf("提交事务失败: %v", err)
            continue
        }

        log.Printf("成功匹配并更新 %d 条数据。", len(matchedData))
        return matchedData, nil
    }

    // 如果重试次数用完,返回错误
    return nil, fmt.Errorf("已达到最大重试次数 %d,任务失败", maxRetries)
}

func main() {
    // 初始化数据库连接
    db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database")
    if err != nil {
        log.Fatalf("数据库连接失败: %v", err)
    }
    defer db.Close()

    // 调用匹配和更新函数
    matchedData, err := MatchAndUpdate(db, 100, 3, [2]float64{0.1, 0.5})
    if err != nil {
        log.Fatalf("匹配和更新失败: %v", err)
    }

    // 打印匹配结果
    log.Printf("匹配结果: %+v", matchedData)
}

  • 举报
回复
@秋声studio 谢谢您的帮助。我之前也试过直接用数据库实现,但随着数据量的增大,效率跟不上。我的想法能不能借助golang自身的数据结构和高速缓存来实现,最后再写入或者更新数据库。

2,348

社区成员

发帖
与我相关
我的任务
社区描述
go语言学习与交流版
社区管理员
  • go语言社区
  • 俺叫西西弗斯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧