locking - 资源预留模式的锁定和隔离
问题描述
我需要用 Spring 和 MariaDB 解决资源预留模式。问题很简单,我有一张来宾表,用于存储活动的客人姓名,我必须确保活动的客人人数必须小于或等于最大容量。
这是表格:
create table guest(
event int,
name varchar(50)
)
create index event on guest (event);
数据库的正确锁定程序和隔离级别是什么?请考虑此代码将在多线程容器中运行。我选择使用“SELECT...FOR UPDATE”锁定表,以将锁定限制在一个事件行中。
// START TRANSACTION
@Transactional
public void reserve(int event, String name){
getJdbc().query("SELECT * FROM guest WHERE id=? FOR UPDATE",event);
Integer count=getJdbc().queryForObject("SELECT COUNT(*) FROM guest WHERE id=?",Integer.class,event);
if(count>=MAX_CAPACITY)
throw new ApplicationException("No room left");
getJdbc().query("INSERT INTO guest VALUES (?,?)",event,name);
}
// COMMIT
我做了一些测试,似乎我需要 READ_COMMITTED 隔离级别,对吗?这是我发现的:
这是我第一次必须更改隔离级别,对此我感到有点惊讶,您能否确认标准 MariaDB 隔离级别 REPETABLE_READ 因这种模式而失败?
解决方案
问题是,在线程 2 中的事务期间,repeatable_read 保证您看到数据库处于事务开始时的状态。因此,当时尚未完成的交易 1 的影响将被隐藏。因此,您将始终看到相同数量的记录,独立于其他交易同时进行的操作。所以两个事务都会插入一条记录。
READ_COMMITTED 意味着根据文档:“每个一致的读取,即使在同一个事务中,设置并读取自己的新快照”。新鲜快照意味着,提交的并发事务的结果将被包括在内。
推荐阅读
- javascript - 如何在反应中将道具传递给孩子?
- ios - ios - 在哪里放置 s.static_framework = true
- asp.net-core - Blazor:单击按钮时调用服务器方法?
- php - 当我尝试填充动态下拉列表时出现 SQLSTATE [42000] 错误
- python - 如何解决 TypeError: create_superuser() got an unexpected keyword argument 'paid' in django
- android - 同一活动 Kotlin 中的抽屉导航和底部导航
- javascript - 单击按钮后如何使一个元素出现?
- ios - 使用 react-native-webrtc 的 ios 应用程序由于非公共 api 而被拒绝
- java - 是否有任何方法可以使用 Salesforce APEX 将图像保存到 Salesforce
- python - 使用 scipy 计算欧几里得距离会给出意想不到的结果