跳至主要内容

删除带外键的表【foreign key constraint fails】报错

遥想当时正在学hibernate的时候,刚好学到了一对多,多对多的关联操作。时间也正是刚好在那是有了一个项目,把各表的间的结构还理清,俗话说学到就要用到,就把这些表的结构都能配置级联关系的都把它配上。没想到就在这里给自己放了个小坑。前几天在一个帖子中看到别人说,尽量少配些ORM约束,数据库的外键约束什么的。当时还不以为然。没想到我就遇到了这个问题,或许对数据库操还是不是很熟悉的人约束真的不要配太多。不过有自然有其的好处就是。
今天在删除一张表的数据的时候报了如下错误:

1
2
3
4
5
6
7
8
9
10
11
12
13
09:55:49.144 [http-nio-8080-exec-6] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Cannot delete or update a parent row: a foreign key constraint fails (`checkin`.`right_umenu`, CONSTRAINT `FKnmg8itd642tdyn6qh1q42h60r` FOREIGN KEY (`menu_detailPid`) REFERENCES `menu_detail` (`id`))
09:55:49.151 [http-nio-8080-exec-6] ERROR org.hibernate.internal.SessionImpl - HHH000346: Error during managed flush [could not execute statement]


org.hibernate.exception.ConstraintViolationException: could not execute statement
 at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59)
 at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
 at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
 at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
 at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:207)
 at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
 at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3198)
 .......

​ 在网上查找后得到的结果和我认为的是一样的,就是外键的问题引发的(当然报错里信息都写了foreign key什么的还不知道,那怎么行(●ˇ∀ˇ●))。网上是说:表之间强制生成了外键,在删除操作时,数据库会检查表间的关系导致无法删除。
解决办法

1
2
3
4
5
SET foreign_key_checks = 0;  // 先设置外键约束检查关闭
 
drop table table1;  // 删除表,如果要删除视图,也是如此
 
SET foreign_key_checks = 1; // 开启外键约束检查,以保持表结构完整性

原理:
MySQL的环境变量中存在一个foreign_key_checks,这是默认检查外键的配置项,如果将其设置为0,则表示不检查外键约束。查看foreign_key_checks的值:

1
show VARIABLES like "foreign%";

然而,然而。我即使把外键约束检查关闭,但是在打开检查的地方又还会报错。这我就无奈了。
不过我在尝试时把,外键的删除项由 RESTRICT 改为 CASCADE 时不但能删除且不影响我的另一个方法的执行,而且的更方便的执行了我想写的方法。
后面又继续查,这是数据库定义外键的一个选项,操作时可以知道update 和delete 后面可以跟的词语有四个 :
no action , set null , set default ,cascade 。

1
2
3
4
5
6
7
no action 表示 不做任何操作,

set null 表示在外键表中将相应字段设置为null

set default 表示设置为默认值(restrict)

cascade 表示级联操作,就是说,如果主键表中被参考字段更新,外键表中也更新,主键表中的记录被删除,外键表中改行也相应删除

所以当我如此设置的时候就把想做的级联删除也都执行了,数据库的很多东西都还要去补啊。

评论

此博客中的热门博文

【图集】言叶之庭(言の葉の庭)

隐约雷鸣 阴霾天空 但盼风雨来 能留你在此 隐约雷鸣 阴霾天空 即使天无雨 我亦留此地 ——万叶集 《言叶之庭》

各数据库无order by时的默认排序

MySQL: 对于 MyISAM 表 ,Select 默认排序是按照物理存储顺序显示的。 而InnoDB 表,会按主键的顺序排列。 Oracle: oracle对无order by的语句返回的结果不进行排序,oracle此时的处理方式是按照数据的物理存储顺序来读取数据。因为rowid是每行数据的地址,所以有时候看起来会像是使用rowid排序的。但这个顺序是可能被打乱的,在表的数据被删除后,rowid会被新插入的数据占用。所以一个无order by查询结果看起来也可能是个杂乱无章的。oracle的数据库实现就一个原则,怎么快怎么效率高就怎么来。大多数情况下不需要排序还非得按主键排序这不是浪费资源么?这和oracle的表结构是有关系的,因为oracle的表结构默认是按堆存放的。按堆存放的意思就是,随便存,存的时候就是乱序的。如果你建表的时候就是建的按索引组织的表,那么它返回的时候就会默认排序了。 sqlserver: 在不指定Order by的情况下,sqlserver会根据执行计划实际查询方式来得到数据,而执行计划会根据sql中很多的因素(的查询列,where条件,order by等)而使用不同的索引,最终出来的结果很可能是不同的。 DB2: DB2的尚不清晰,排序好像与sort heap相关。