提问者:小点点

MySQL查询给我不正确或旧的数据


我有一个表,其中的值如下所示,

现在,我有两个线程正在尝试做同样的事情。它们如下。

  1. 从表中提取未进行或未完成的记录。
  2. 将其标记为未进展。
  3. 处理记录。
  4. 将其标记为完成。

我实现了以下内容,以确保两个线程不会同时拾取相同的记录。

  1. “从状态不在('Complete'、'InProgress')限制1的表中选择*from以更新”,从表中获取合适的记录。
  2. 在一个事务中执行了步骤1和步骤2,这样表就变成读锁定,直到拾取的记录被标记为未进行。

但是,我面临以下问题
如果线程-1正在获取一个记录,而它还没有将该记录标记为“Inprogress”,则另一个线程(线程-2)尝试进行同样的操作。线程-2有时首先获取线程-1已经选取的记录,并在线程-1事务解除锁后返回状态为“Inprogress”的相同记录。

除了在获取记录后添加状态值检查之外,我不知道如何解决这个问题,但我认为可能有一个更好的方法。

如果有更好的方法请告诉我。

下面是负责提取要处理的记录的方法的示例代码,

//存储库

class TableRepository implements JpaRepository<Table, Long> {
 @Query(value = "select * from table where status not in ('COMPLETE', 'INPROGRESS') limit 1 for update", nativeQuery=true)
 Table getOneValidRecord(); 
}

//服务类别

class TableService {

@Autowired
private TableRepository repository;

@Transactional(propagation = Propagation.REQUIRES_NEW)
public Table getOneValidRecord() {

Table table = repository.getOneValidRecord();
table.setStatus("INPROGRESS");
return repository.save(table);
}

}

共1个答案

匿名用户

必须使用中间保留状态。在SQL级别:

步骤1.尽量保留。

UPDATE table
SET status = 'Thread 1 reserved'
WHERE status = 'PENDING'
ORDER BY id
LIMIT 1

第二步。检查预订是否成功。

SELECT COUNT(*)
FROM table
WHERE status = 'Thread 1 reserved'

如果输出为零,则线程2过度保留了同一行。转到步骤1。如果输出超过1,则发生紧急情况。呼叫接线员。

步骤3.处理行。

UPDATE table
SET status = 'INPROGRESS'
WHERE status = 'Thread 1 reserved'
ORDER BY id
LIMIT 1