Sql 当更新基于先前选择的计数时,避免竞争条件

Sql 当更新基于先前选择的计数时,避免竞争条件,sql,sqlite,Sql,Sqlite,我担心数据库支持的应用程序中的竞争条件。我的应用程序允许用户在类中保留一个位置。如果所有的点都被选中,那么它们就会被列入等待名单。在大大简化的伪代码中,我做了如下工作: 1 spots = SELECT total_spots FROM classes WHERE class_id = 200; 2 regs = SELECT COUNT(*) FROM registrations WHERE class_id = 200; 3 wl = spots > regs 4 IN

我担心数据库支持的应用程序中的竞争条件。我的应用程序允许用户在类中保留一个位置。如果所有的点都被选中,那么它们就会被列入等待名单。在大大简化的伪代码中,我做了如下工作:

1  spots = SELECT total_spots FROM classes WHERE class_id = 200;
2  regs  = SELECT COUNT(*) FROM registrations WHERE class_id = 200;
3  wl    = spots > regs
4  INSERT INTO registrations ( user_id, class_id, on_waitlist ) VALUES ( 500, 200, wl ); 
如果classes表中的total_spots发生了更改,或者另一个用户在我们读取第2行之后在registrations表上进行了插入,会发生什么情况

将整个事务包装在一个事务中是否足够?我读了一些关于MySQL中SELECT FOR UPDATE的内容。我目前正在使用SQLite,但如果需要,我可以迁移到MySQL。

SQLite的事务


如果将整个内容包装到事务中,则同一数据库的其他连接无法同时进行任何更改。

您也可以在插入中选择:

insert into registrations (user_id, class_id, on_waitlist) 
 values ( 500, 200,
   (SELECT total_spots FROM classes WHERE class_id = 200) <  
   (SELECT COUNT(*) FROM registrations WHERE class_id = 200)
 );

这将是我处理它的首选方法,但我给出的示例大大简化了。在允许注册之前,需要进行许多检查。我不确定我是否能在一个语句中获得所有更新。那么事务就是你的朋友。这难道不能保证所有更新都被执行或回滚吗。当我读取SQLite时,在事务中,您在第一次读取时会得到一个共享锁,在第一次写入时会得到一个保留锁。当您持有共享锁(即第4行中的更新之前)时,另一个进程不能写入吗?共享锁阻止其他任何人获取保留锁。