【问题标题】:MySQL Update value to unique for specific month/year combinationMySQL 将特定月/年组合的值更新为唯一
【发布时间】:2020-05-10 09:38:01
【问题描述】:

我的表记录包含:id、year、month、number、value

创建记录时,number 设置为 NULL

稍后当记录注册时,我需要为该记录创建唯一的 number,这对于特定的 yearmonth 组合是唯一的,并且应该从本月存在的最后一个 number 开始增加。同时其他人可能会尝试这样做,并且很可能会选择与我相同的递增数字。如果同时创建它们,我需要避免重复。

如果给定月份不存在数字,则应以 1 开头。

数字值可以在表格中重复,但不能用于相同的年/月组合。

我想这样做:

  1. 锁表
  2. 对现有值进行降序排序(对于给定的月/年)并获得第一个
  3. 增加它并更新特定记录
  4. 解锁表

但我想知道是否有更干净和优雅的方法来解决它?我想避免锁定表格太久,或者在应用端出现问题时冒着被锁定的风险。

问候。

按要求提供测试数据:

CREATE TABLE RECORDS (`id` int(11) NOT NULL AUTO_INCREMENT, `year` int(4), `month` int(4), `number` int(4), `value` int(4), PRIMARY KEY (`id`));
INSERT INTO RECORDS (year, month, number, value) VALUES
(2019, 10, 1, 100),
(2019, 10, 2, 200),
(2019, 10, 5, 300),
(2019, 10, 3, 400),
(2019, 10, 4, 500),
(2019, 10, 6, 600),
(2019, 10, NULL, 700),
(2019, 10, NULL, 800),
(2019, 10, NULL, 900),
(2019, 11, 1, 100),
(2019, 11, NULL, 200),
(2019, 11, NULL, 300),
(2019, 11, 2, 400),
(2019, 11, 3, 500),
(2019, 11, NULL, 600),
(2019, 11, 4, 700),
(2019, 12, 1, 100),
(2019, 12, 2, 300),
(2019, 12, NULL, 200),
(2019, 12, NULL, 500),
(2019, 12, NULL, 600),
(2019, 12, NULL, 700),
(2019, 12, NULL, 800);

小提琴: https://www.db-fiddle.com/f/d4Dfs5zcBUU1X95TaaHbNx/0#&togetherjs=93fntrtw0y

【问题讨论】:

  • 为什么人们要为自己设置这些障碍?只需存储一个 id 并继续前进。
  • 我不能无视我收到的要求。编号格式很严格...
  • 哦,我希望你收费合理。 - 你的方法似乎和其他方法一样好。
  • MariaDB-10.3 有SEQUENCEs
  • 但是我认为您将数据显示存储和检索的问题与数据显示的问题混淆了。

标签: mysql locking


【解决方案1】:

我相信这些是根据您的需要最有效地更新的基本步骤。

  1. yearmonthnumber(按此顺序)上创建唯一索引,以防止欺骗并允许过滤锁定。
  2. 在递增数字时使用FOR UPDATE,以防止其他事务在更新期间读取行,同时仅锁定具有相应年份和月份的行,而不是整个表。
BEGIN;
SELECT MAX(NUMBER)
FROM RECORDS
WHERE YEAR = ? AND MONTH = ?
FOR UPDATE;
UPDATE RECORDS
    SET NUMBER = ?
    WHERE YEAR = ? AND MONTH = ?;
COMMIT;

【讨论】:

  • 谢谢!正是我正在寻找的。 CREATE TABLE RECORDS (id int(11) NOT NULL AUTO_INCREMENT, year int(4), month int(4), number int(4), value int(4), PRIMARY KEY (id), UNIQUE KEY unique_number (year,month,number)); 然后BEGIN; SELECT @current := MAX(number) FROM RECORDS WHERE year = ? AND month = ? FOR UPDATE; UPDATE RECORDS SET NUMBER = ifnull(@current, 0) + 1 WHERE year = ? AND month = ? AND id = ?; COMMIT;
猜你喜欢
  • 2023-04-07
  • 1970-01-01
  • 2020-01-21
  • 1970-01-01
  • 2015-02-23
  • 2018-05-07
  • 2015-05-21
  • 2015-05-11
  • 1970-01-01
相关资源
最近更新 更多