我必须从用户那里获得关于他们技能的意见。我有一个以 id 作为主键的技能表。在另一个表中,我将用户 ID 和技能 ID 存储为多对多关系。现在的问题是我怎么知道用户输入的技能已经在我的技能表中?因为我必须将技能 ID 放在多对多关系表中。我是每次运行一个 select 语句还是有一些有效的解决方案可用?谢谢,
2 回答
这个问题没有一步到位的解决方案。首先,您需要检查技能表中是否存在技能并获取 ID,如果不存在则插入并获取 ID。然后在您的 PeopleSkills 表中插入一行,其中包含人员的 ID 和技能...
我怎么知道用户输入的技能已经在我的技能表中?
在并发环境中,您无法知道这一点。即使您执行 SELECT,也只会告诉您在 SELECT 执行时行是否存在 - 它不会告诉您该行现在是否存在。例如,即使 SELECT 返回一个空结果,并发事务也可能在您收到 SELECT 结果的几毫秒内插入了该行。
所以你要么大幅减少并发性(例如通过表锁),要么学会忍受它......
当只需要 INSERT 时
我建议您简单地尝试 INSERT(不带 SELECT),然后忽略可能的 PRIMARY KEY 违规1。
如果您执行了单独的 SELECT 和 INSERT 步骤,您仍然必须为 PK 违规做好准备,因为并发事务可以在您的 SELECT 之后但在您的 INSERT 之前执行 INSERT(并提交)。那么,为什么要首先使用 SELECT 呢?
当需要 INSERT 或 UPDATE 时
如果联结表包含除 FK 字段之外的其他字段,那么您可能希望将它们更新为新值,因此您必须首先执行 SELECT 以确定该行是否需要插入或更新。
在这种情况下,请考虑使用 SELECT ... FOR UPDATE(或等效语法)提前锁定行。2或者,一些 DBMS 在单个命令中提供“插入或更新”(又名“UPSERT”)(例如:MySQL INSERT ... ON DUPLICATE KEY UPDATE)。
1但要小心只忽略 PK 违规 - 不要只是盲目地“吞下” FK 或 CHECK 违规等......
2为了避免在您有机会更新它之前将其删除(仍然可能违反 INSERT PK)。更糟糕的是,并发事务可能会更新行,让您的事务默默地覆盖其他事务的值,而不会意识到它们曾经存在过。