是否可以暂时禁用MySQL中的约束?

我有两个Django模型,每个都有一个指向另一个的外键。删除一个模型的实例将返回一个错误,因为外键约束:

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()  #a foreign key constraint fails here

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

是否有可能暂时禁用约束并删除?


当前回答

如果键字段是可空的,那么你也可以在尝试删除它之前将值设置为空:

cursor.execute("UPDATE myapp_item SET myapp_style_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed() 

cursor.execute("UPDATE myapp_style SET myapp_item_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

其他回答

如果键字段是可空的,那么你也可以在尝试删除它之前将值设置为空:

cursor.execute("UPDATE myapp_item SET myapp_style_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed() 

cursor.execute("UPDATE myapp_style SET myapp_item_id = NULL WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_item WHERE n = %s", n)
transaction.commit_unless_managed()

cursor.execute("DELETE FROM myapp_style WHERE n = %s", n)
transaction.commit_unless_managed()

与其禁用约束,不如将其永久修改为ON DELETE SET NULL。这将完成类似的事情,你不需要打开和关闭键检查。像这样:

ALTER TABLE tablename1 DROP FOREIGN KEY fk_name1; //get rid of current constraints
ALTER TABLE tablename2 DROP FOREIGN KEY fk_name2;

ALTER TABLE tablename1 
  ADD FOREIGN KEY (table2_id) 
        REFERENCES table2(id)
        ON DELETE SET NULL  //add back constraint

ALTER TABLE tablename2 
  ADD FOREIGN KEY (table1_id) 
        REFERENCES table1(id)
        ON DELETE SET NULL //add back other constraint

看看这个(http://dev.mysql.com/doc/refman/5.5/en/alter-table.html)和这个(http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html)。

要在全局范围内关闭外键约束,请执行以下操作:

SET GLOBAL FOREIGN_KEY_CHECKS=0;

完成后记得把它调回去

SET GLOBAL FOREIGN_KEY_CHECKS=1;

警告:只有在进行单用户模式维护时才应该这样做。因为这可能会导致数据不一致。例如,当您使用mysqldump输出上传大量数据时,它将非常有用。

对我来说,SET FOREIGN_KEY_CHECKS=0;是不够的。 我仍然有一个com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException。

我不得不添加ALTER TABLE myTable禁用键;。

So:

SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE myTable DISABLE KEYS;
DELETE FROM myTable;
ALTER TABLE myTable ENABLE KEYS;
SET FOREIGN_KEY_CHECKS=1;

将外键约束设置为0并不是一个好主意,因为如果这样做,数据库将不能确保它没有违反引用完整性。这可能导致不准确、误导或不完整的数据。

使用外键是有原因的:因为子列中的所有值都应该与父列中的值相同。如果没有外键约束,子行可以有不在父行中的值,这将导致不准确的数据。

For instance, let's say you have a website for students to login and every student must register for an account as a user. You have one table for user ids, with user id as a primary key; and another table for student accounts, with student id as a column. Since every student must have a user id, it would make sense to make the student id from the student accounts table a foreign key that references the primary key user id in the user ids table. If there are no foreign key checks, a student could end up having a student id and no user id, which means a student can get an account without being a user, which is wrong.

想象一下,如果它发生在大量数据上。这就是为什么你需要外键检查。

最好弄清楚是什么导致了错误。最有可能的情况是,您试图从父行删除而不删除子行。尝试先从子行删除,再从父行删除。