在mysql中创建不可变字段

时间:2013-07-02 11:31:31

标签: mysql

我想制作一个TIMESTAMP字段DEFAULT CURRENT_TIMESTAMP,用于“创建时间”。但是,如果有人或某种方式发生变化TIMESTAMP,我的数据将不一致。

有没有办法可以确保它不会改变,除非我删除行并重新插入它,而不是应用程序级别?


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

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;

6 个答案:

答案 0 :(得分:6)

由于我的评论得到了赞赏,这是扩展版本。

我个人认为不可能。

无论如何,你可以尝试一些事情:

  1. 确保只有您的应用程序可以在数据库上写入

  2. 像这样写一个触发器(伪代码!)

    create trigger prevent_change_timestamp on tbl_name
    before update
    #fetch old row value
    #verify if the timestamp field has been changed
    #raise an error (any SQL error will do)
    
  3. 或者像这样

    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
    
  4. 如果可能的话,我个人会选择第3种选择。无论如何,第二个也很好。除非必要,否则我不会依赖第一个选项(例如:无法访问触发功能)

    此处有更多信息:reference

答案 1 :(得分:2)

数据库应用程序不能将此功能作为标准提供,这很有趣:不仅仅是为了创建" timestamp字段,但是对于诸如自动增量id字段之类的内容,以及您在创建记录时可能要设置的任何杂项值,然后永远不允许更改...想知道原理是什么?

答案 2 :(得分: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):触发后

中不允许更新NEW行

接受由BEFORE替换的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

答案 3 :(得分:1)

如果您使用InnoDB,实际上可以非常巧妙地做到这一点。

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

施加限制,例如" ON UPDATE RESTRICT"。

总结:

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;

答案 4 :(得分:0)

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

答案 5 :(得分:-1)

将这个想法更进一步(对于我们这些仍然坚持使用遗留版本的MySQL的人来说),您可以同时拥有受保护的&默认的create_stamp和一个自动更新的update_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 ;