提问人:Alex 提问时间:9/26/2023 更新时间:9/28/2023 访问量:42
使用 innoDB 存储引擎在 mysql 中获取组合密钥(年份/数字)
Obtaining a combined key (year/number) in mysql with innoDB storage engine
问:
我想在innoDB表中创建一个组合键,该表已经有一个“ID”列,该列具有自动递增值,用作主键。
假设我们在 “test_db” 中有以下 “test_table”:
我为“test_table”触发了“inc year_num”:
SET New.num_field := IFNULL(
( SELECT MAX(num_field)+1
FROM test_table
WHERE year_field = New.year_field ), 1)
这个触发器(“插入之前”)似乎效果很好:
然而 il 让我怀疑:在多次同时插入的情况下,即使具有不同的“ID”,它也能生成相同的组合键(年份/数字)吗? 如果是这样,我该如何解决问题?
另一个问题:考虑到在多用户环境中使用,使用此触发器会减慢表速度吗?
答:
0赞
Rick James
9/26/2023
#1
要处理多个线程,请使用事务:
START TRANSACTION;
get the new num_field
put that value into the table
etc
COMMIT;
似乎没有必要有;只需拥有.id
PRIMARY KEY(year_field, num_field)
另一个说明:将在更高版本的 MySQL 中删除。(它在 8.0.17 中已“弃用”。有一些简单的解决方法。ZEROFILL
除了默认值之外,您几乎永远不需要隔离级别,因此请忽略该课程(暂时)。
一个事务可能会也可能不会等待另一个事务完成。单个行被锁定;如果没有冲突的锁,则两个事务可以并行进行。
TRIGGER
并且是正交特征。例如,触发器可以包含所需的所有 SQL 语句,也可以调用封装这些语句的过程。PROCEDURE
评论
0赞
Alex
9/27/2023
谢谢。我刚刚进入MySQL,对事务不熟悉。昨天我稍微研究了这个主题,我明白了隔离有 4 个级别。您能解释一下我的情况的正确隔离级别是多少以及如何设置它吗?如果我理解正确,我需要每笔交易在上一笔交易完成之前才开始。我需要更改分隔符吗?如果/否则,回滚?如果您能发布正确的代码,我将不胜感激。最后一件事:代码是直接进入触发器,还是我需要创建一个包含调用它的触发器的存储过程?
0赞
Rick James
9/28/2023
@Alex - 我添加到我的答案中。
0赞
Alex
9/30/2023
对不起@RickJames我向你保证,这是我最后一次发消息。如果两个同时发生的事务(T1 和 T2)需要插入一行,则每个事务都将搜索最大值“num_field”,其中“year_field”的值等于要插入的值。想象一下,要插入的“year_field”的值是“2023”,而年份等于“2023”的“num_field”的最大值是“5”,那么两者都不可能通过在“year_field”中写“2023”和在“num_field”中写“6”来获取这个值,从而产生违反组合字段唯一性规则的错误?
0赞
Rick James
9/30/2023
@Alex - 交易内部的任何内容都可能需要在末尾添加一个子句。这尤其适用于“获取新num_field”-->。这会提醒其他事务正在发生某些事情。SELECTs
FOR UPDATE
SELECT MAX(num_field)+1 FROM tbl FOR UPDATE
num_field
评论
(year_field, num_field)