java - 当多个线程正在等待的锁定行被删除时,MySQL 会发生什么?
问题描述
我有一个要求,其中一个请求必须访问数据库中最顶层的行,读取它并删除它,通过锁定特定行一次性完成。
这里的用例是 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());
}
}
我难以理解的是,当多个线程试图执行相同的方法时,这将如何发挥作用。
比如说,线程T1和T2正在并行执行相同的方法。在任何给定点,T1 获取第一行 R1 上的锁,而 T2 等待同一行上的锁。
到 T1 完成时,行本身并不存在,那么 T2 将如何进行?
如果我们在整个表上获得锁,那么随着写入负载的增加,这可能会导致性能下降。
处理此问题的最佳方法是什么,以免锁定成为可扩展性的瓶颈?
解决方案
完成后将其删除
你说的是毫秒后吗?还是几个小时后?锁定行“直到完成”最多几秒钟是可行的。对于更长的“锁”,您需要发明一种不同的机制。(如果需要,我们可以讨论。)
这是 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;这是本站的通用语言。)
推荐阅读
- screenshot - Direct3D 是否从 GDI32.dll 调用 bitBlt
- python - 不支持的操作数类型:“str”和“str”
- java - JFrame 之间的数据传输
- angular - 模板解析错误 Angular
- google-sheets - 计算数据透视表的统计差异
- leaflet - Leaflet - 允许以高于最大缩放比例切换到另一个基础层
- javascript - 如何使用 Canvas 将我的线条图居中对齐?
- java - 需要构造函数中的 Spring-Boot 通用类型
- asp.net-core - 在提交时从 textarea 值设置 asp-route-content 参数
- c# - 如何在视图中获取当前操作名称