在mysql中创建不可变字段

在mysql中创建不可变字段,mysql,Mysql,我想制作一个时间戳字段默认当前时间戳,用于“创建时间”目的。但如果某人或某物更改了时间戳,我的数据将不一致 是否有一种方法可以确保它不会更改,除非我删除该行并重新插入它,而不是应用程序级别 根据提供的建议答案,我可以解决类似的问题 CREATE TRIGGER consistency1 BEFORE UPDATE ON table1 FOR EACH ROW BEGIN IF NEW.creationtime != OLD.creationtime THEN SET NE

我想制作一个
时间戳
字段
默认当前时间戳
,用于“创建时间”目的。但如果某人或某物更改了时间戳,我的数据将不一致

是否有一种方法可以确保它不会更改,除非我删除该行并重新插入它,而不是应用程序级别


根据提供的建议答案,我可以解决类似的问题

CREATE TRIGGER consistency1 BEFORE UPDATE ON table1
FOR EACH ROW
BEGIN
    IF NEW.creationtime != OLD.creationtime THEN
       SET NEW.creationtime = OLD.creationtime;
    END IF;
END;
create trigger revert_change_timestamp on tbl_name
after update
#fetch pre-change row value
#update the row with the "old" value in place of the new one

这里您可以做的是,当一行被更新时,您可以在表上编写一个
触发器。在该触发器中,您可以比较新旧值,如果它们不同,则可以用旧值覆盖新值。

由于我的评论受到赞赏,这里是扩展版本

我个人认为这是不可能的

无论如何,有几件事你可以试试:

  • 确保只有您的应用程序才能在数据库上写入

  • 编写这样的触发器(伪代码!)

  • 还是像这样

    CREATE TRIGGER consistency1 BEFORE UPDATE ON table1
    FOR EACH ROW
    BEGIN
        IF NEW.creationtime != OLD.creationtime THEN
           SET NEW.creationtime = OLD.creationtime;
        END IF;
    END;
    
    create trigger revert_change_timestamp on tbl_name
    after update
    #fetch pre-change row value
    #update the row with the "old" value in place of the new one
    
  • 如果可能的话,我个人会选择第三种选择。不管怎样,第二个也不错。除非必要,否则我不会依赖第1个选项(例如:无法访问触发器功能)


    这里有更多信息:

    我在MySQL 5.1中尝试了这个,但出现了一个错误

    DELIMITER //
    
    CREATE TRIGGER member_update_0
        ->     AFTER UPDATE ON members
        ->     FOR EACH ROW
        -> BEGIN
        ->     IF NEW.id != OLD.id THEN
        ->        SET NEW.id = OLD.id;
        ->     END IF;
        -> END;//
    
    错误1362(HY000):在after触发器中不允许更新新行

    接受相同的触发器,用“后”替换为“前”; 对我来说,这是一种违反直觉的方法,但它是有效的

    delimiter ;
    UPDATE members SET id=11353 WHERE id=1353;
    Query OK, 0 rows affected (0.00 sec)
    Rows matched: 1  Changed: 0  Warnings: 0
    

    如果您使用InnoDB,实际上可以非常灵活地完成这项工作

    创建另一个只包含一列的表。该列应该有一个外键(因此本解决方案中的innodb要求)指向所讨论的原始表的不可变列

    设置一个类似“更新限制”的限制

    总之:

    CREATE TABLE original (
         ....
         immutable_column ...
         INDEX index1(immutable_column)
         ....
    ) ENGINE=INNODB;
    
    CREATE TABLE restricter (
         .....
         col1,
         INDEX index2(col1),
         FOREIGN KEY (col1) REFERENCES original (immutable_colum) ON UPDATE RESTRICT ON DELETE CASCADE
    ) ENGINE=INNODB;
    

    有趣的是,数据库应用程序并没有提供这种标准功能:不仅针对“已创建”的时间戳字段,而且针对自动增量id字段等内容,以及您可能希望在创建记录时设置的任何杂项值,然后决不允许更改这些值。。。想知道理由是什么吗?

    进一步考虑这个想法(对于我们这些仍然坚持使用传统版本的MySQL的人来说),您可以拥有受保护和默认的create\u stamp和自动更新\u stamp,如下所示:

    如果你有这样的桌子

    CREATE TABLE `csv_status` (
      `id` int(11) NOT NULL primary key AUTO_INCREMENT,
      `create_stamp` datetime not null,
      `update_stamp` timestamp default current_timestamp on update current_timestamp,
      `status` enum('happy','sad') not null default 'happy'
    );
    
    然后你可以在上面定义这些触发器

    drop trigger if exists set_create_stamp ;
    create definer = CURRENT_USER trigger set_create_stamp BEFORE INSERT on 
    csv_status for each row
      set NEW.create_stamp = now();
    
    drop trigger if exists protect_create_stamp ;
    delimiter //
    create definer = CURRENT_USER trigger protect_create_stamp BEFORE UPDATE on 
    csv_status for each row
      begin
        if NEW.create_stamp != OLD.create_stamp then
        set NEW.create_stamp = OLD.create_stamp;
        end if;
      end;//
    delimiter ;
    

    我认为这是不可能的,但也许你可以在用@STTLCU更新greed之前找到一个解决方法,使用触发器。我在这里找到了这个(以前的值检查和覆盖):@Rolice谢谢,我已经添加了您在我的answer@STTLCU,你欢迎:)触发器是魔鬼的玩物。引用一些“数据库应用程序不提供标准的此功能”的来源,可以大大改进此答案.虽然有一个触发器并不理想,但我认为仅仅为了实现不变性而添加整个表并不是一个优雅的解决方案。