【问题标题】:How to insert data in a column with a trigger after data is inserted in a row?将数据插入一行后,如何使用触发器在列中插入数据?
【发布时间】:2019-12-17 14:37:09
【问题描述】:

我在 Laravel 中有一个程序,用户注册后他们需要一个徽章编号,我希望在他们在数据库中注册后随机生成该编号。我应该使用触发器,但我在语法上很挣扎。

用户表

id bigint(20)
name varchar(255)
surname varchar(255)
nr_legitimatie varchar(255)

我希望“nr_legitimatie”字段是唯一的。 这是我尝试过的,但没有成功

触发器

CREATE OR REPLACE TRIGGER numar_leg
AFTER INSERT ON users
FOR EACH ROW
DECLARE
    legitimatie VARCHAR(191)
BEGIN
    legitimatie =('
    SELECT FLOOR(RAND() * 99999) AS random_num
    FROM numbers_mst
    WHERE "random_num" NOT IN (SELECT my_number FROM numbers_mst) 
    LIMIT 1' );
    set `users`.`nr_legitimatie` = legitimatie;
 END;

【问题讨论】:

  • 通常我们会在BEFORE INSERT 触发器中处理对列的赋值,而不是AFTER INSERT 触发器。好像我们正在跟踪已使用的随机值,将它们存储在一个表中,似乎我们还想存储我们用于当前行的新值。

标签: mysql database laravel triggers


【解决方案1】:

这是一个 MySQL BEFORE INSERT 触发器示例,它为 nr_legitimatie 列分配一个值。

DELIMITER $$

DROP TRIGGER numar_leg$$

CREATE TRIGGER numar_leg
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
    DECLARE li_nrn BIGINT DEFAULT NULL;
    DECLARE li_cnt BIGINT DEFAULT 1;
    WHILE li_cnt > 0 DO
       -- generate a new random number
       SELECT FLOOR(RAND()*99999) AS nrn INTO li_nrn;
       -- check if the new random number is already used 
       SELECT COUNT(1) INTO li_cnt FROM users u WHERE u.nr_legitimatie = li_nrn;
    END WHILE;
    SET NEW.nr_legitimatie := li_nrn;
END$$

DELIMITER ;

请注意,这保证分配给nr_legitimatie 的值将是唯一的,因为触发器中的代码受制于竞争条件。两个(或更多)同时会话可能会发现相同的随机数尚未“未使用”,并且每个会话都将使用它。 (对现有值的检查在分配给列之前。)

如果要保证唯一性,我们应该在users表的列上添加一个UNIQUE约束(UNIQUE KEY)。

我们还可以使用单独的表来跟踪使用的数字,在列上使用 UNIQUE 约束,我们可以尝试插入,并在尝试插入重复项时捕获错误。

如果我们引入一个跟踪表,例如

CREATE TABLE nrn (nrn BIGINT PRIMARY KEY) ;

然后我们可以避免竞争条件,同时对现有副本进行测试并保留新值。像这样的:

DELIMITER $$

CREATE TRIGGER numar_leg
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
    DECLARE li_nrn BIGINT DEFAULT NULL;
    DECLARE li_dup BIGINT DEFAULT 1;
    DECLARE CONTINUE HANDLER FOR 1062 SET li_dup := 1;
    WHILE li_dup > 0 DO
       SELECT FLOOR(RAND()*99999) AS nrn INTO li_nrn;
       SET li_dup := 0;
       INSERT INTO nrn (nrn) VALUES (li_nrn);
    END WHILE;
    SET NEW.nr_legitimatie := li_nrn;
END$$

DELIMITER ;

这里的边缘情况是触发器被执行,一个新的随机数被生成并保留,但是由于某种原因插入users表失败了,我们没有发出ROLLBACK。如果我们发出 ROLLBACK,那么我们的新随机数预留也将被回滚(除非 nrn 是 MyISAM 表)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-20
    • 2017-09-19
    • 1970-01-01
    • 2013-05-16
    • 2014-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多