如何用SQL唯一索引限制未完成状态的UserTestAttempt记录数量?
用SQL条件唯一索引实现测试尝试的创建限制
可以通过SQL的**条件唯一索引(Partial Unique Index)**实现这个业务限制,不需要完全依赖代码控制。
核心逻辑很明确:只对状态为REGISTERED或IN_PROGRESS的记录,强制userId和testId的唯一性;状态为PASSED或FAILED的记录不受该约束,允许用户重复创建新的测试尝试。
下面是主流数据库的实现示例:
MySQL
CREATE UNIQUE INDEX idx_user_test_active_attempt ON UserTestAttempt (userId, testId) WHERE status IN ('REGISTERED', 'IN_PROGRESS');
PostgreSQL
CREATE UNIQUE INDEX idx_user_test_active_attempt ON "UserTestAttempt" ("userId", "testId") WHERE status IN ('REGISTERED', 'IN_PROGRESS');
Oracle
Oracle没有直接的部分唯一索引语法,但可以通过函数索引间接实现:
CREATE UNIQUE INDEX idx_user_test_active_attempt ON UserTestAttempt ( CASE WHEN status IN ('REGISTERED', 'IN_PROGRESS') THEN userId ELSE NULL END, CASE WHEN status IN ('REGISTERED', 'IN_PROGRESS') THEN testId ELSE NULL END );
原理是Oracle的唯一索引会忽略NULL值,当状态为PASSED或FAILED时,CASE语句返回NULL,不会触发唯一约束;只有状态符合活跃状态时,才会强制userId+testId的唯一性。
这种数据库层面的约束优势很明显:能避免代码层面可能出现的并发问题(比如多个请求同时校验、创建时,因为时间差导致的重复记录),比纯代码控制更可靠。
如果你的数据库不支持条件唯一索引(比如某些老旧版本的数据库),才需要结合代码逻辑+事务来控制,但目前主流的关系型数据库都支持这类特性。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

