【问题标题】:What happens in MySQL when a locked row, which multiple threads are waiting on, gets deleted?当多个线程正在等待的锁定行被删除时,MySQL 会发生什么?
【发布时间】:2021-12-15 15:27:40
【问题描述】:

我有一个要求,请求必须获得对数据库中最顶层行的访问权限,读取并删除它,通过锁定特定行一次性完成。

这里的用例是 URL 缩短应用程序将查询此表以获取预先生成的 URL 密钥并在完成后将其删除。

我使用的是Spring Data JPA,所以我将添加以下代码

URLKeyEntity.java

@Entity(name = "urlKeyEntity")
@Table(name = "url_key")
@Data
public class URLKeyEntity {

 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 private Long id;
 private String urlKey;
}

URLKeyRepository.java

@Repository
public interface URLKeyRepository extends JpaRepository<URLKeyEntity, Long> {

 @Lock(LockMode.PESSIMISTIC_WRITE)
 @Query("SELECT u FROM urlKeyEntity u ORDER BY u.id")
 List<URLKeyEntity> fetchTopRow(Pageable p);
}

URLKeyService.java

@Service
public class URLKeyService {

 @Autowired
 private URLKeyRepository urlKeyRepository;

 @Transactional
 public String getUrlKey() {
  final URLKeyEntity u = urlKeyRepository.findTopRow(PageRequest.of(0,1));
  final String key = u.get(0).getUrlKey();
  urlKeyRepository.delete(u.getId());
 }
}

我难以理解的是,当多个线程试图执行相同的方法时,这将如何发挥作用。

比如说,线程 T1T2 正在执行相同的方法并行。在任何给定时间点,T1 都会获取第一行 R1 上的锁,而 T2 则等待同一行上的锁。

到 T1 完成时,行本身并不存在,那么 T2 将如何进行?

如果我们在整个表上获取锁,那么随着写入负载的增加,这可能会导致性能下降。

处理此问题的最佳方法是什么,以免锁定成为可伸缩性的瓶颈?

【问题讨论】:

    标签: java mysql spring multithreading spring-data-jpa


    【解决方案1】:

    完成后删除

    你说的是毫秒后吗?还是几个小时后?锁定行“直到完成”最多几秒钟是可行的。对于更长的“锁”,您需要发明一种不同的机制。 (如果需要,我们可以讨论。)

    这是InnoDB如何锁定行,让你做一些工作,然后删除它:

    START TRANSACTION;
    SELECT id, ...
         ORDER BY ... DESC
         LIMIT 1
         FOR UPDATE;   -- 'lock' the last row
    ... do the work
    DELETE ... WHERE id = ...;
    COMMIT;
    

    如果您需要中断该语句序列,请执行ROLLBACK

    如果您希望有多个线程分别处理该表中的某行,请这样说。我所介绍的基本上一次只能做一个“最后一行”;其他线程必须等待。

    (如果您想讨论您的代码,请提供生成的 SQL;这是本站的通用语言。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-04
      相关资源
      最近更新 更多