2,348
社区成员




在数据库中,存放有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
求思路或方案,谢谢!
希望能帮到你
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)
}