如果父子表实体引用了父表的外键和父表的主键,如何级联删除它们



我有这样的scenario -> event -> plan表关系,它们是:

场景表:

CREATE TABLE `scenario` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`plan_cycle_id` bigint(20) unsigned NOT NULL,
`created_by` varchar(255) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `scenario_table_plan_cycle_id_fk` (`plan_cycle_id`),
CONSTRAINT `scenario_table_plan_cycle_id_fk` FOREIGN KEY (`plan_cycle_id`) REFERENCES `planning_cycle` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

事件表

CREATE TABLE `event` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`start_date` timestamp NULL DEFAULT NULL,
`end_date` timestamp NULL DEFAULT NULL,
`scenario_id` bigint(20) unsigned NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created_by` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_scenario_id` (`scenario_id`),
CONSTRAINT `fk_scenario_id` FOREIGN KEY (`scenario_id`) REFERENCES `scenario` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

计划表

CREATE TABLE `plan` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`scenario_id` bigint(20) unsigned NOT NULL,
`input` json DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created_by` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `plan_scenario_id` (`scenario_id`),
CONSTRAINT `FKnjhfw18pms9j2yhtvu954hcsi` FOREIGN KEY (`scenario_id`) REFERENCES `scenario` (`id`), // this was not there in create table command but later added by mysql //
CONSTRAINT `plan_scenario_id` FOREIGN KEY (`scenario_id`) REFERENCES `event` (`scenario_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

现在,我想级联删除一些特定场景id的场景、事件和计划。当没有孙辈时,场景和事件会像预期的那样被删除。但是,当计划中出现引用scenario_id的新条目时,我在删除时收到了这个错误:

java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`db_dev`.`plan`, CONSTRAINT `plan_scenario_id` FOREIGN KEY (`scenario_id`) REFERENCES `event` (`scenario_id`))

我尝试在eventEntity.java中加载EAGER,如下所示:

@OneToMany(fetch = FetchType.EAGER, mappedBy = "scenario", cascade = CascadeType.ALL)
private List<planEntity> planEntityList;

在planEntity.java中是这样的:

@ManyToOne
@JoinColumn(name = "scenario_id", referencedColumnName = "id")
private ScenarioEntity scenario;

如何通过*entity.java文件处理此情况?

在MySql中,当表是InnoDB时,您可以添加外键约束。外键检查是在更新或删除记录时进行的。外键检查的结果取决于表的设计,因为您可能允许级联更新或删除,或阻止更新或删除过程
以下是一个父级示例:

CREATE TABLE parent (
id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;

允许父表删除或更新父表的(id(字段的子表示例(子表也将被删除(:

CREATE TABLE child (
id INT,
parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id)
REFERENCES parent(id)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB;

阻止更新父表的(id(字段但允许删除父表的子表示例。(子项也将被删除(:

CREATE TABLE child (
id INT,
parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id)
REFERENCES parent(id)
ON DELETE CASCADE 
) ENGINE=INNODB;

阻止父表删除或更新父表的(id(字段的子表示例。这将给出类似于";无法删除或更新父行:外键约束失败":

CREATE TABLE child (
id INT,
parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id)
REFERENCES parent(id)
) ENGINE=INNODB;

使用外键约束时有四个选项:

RESTRICT|CASCADE|SET NULL | NO ACTION|SET DEFAULT

RESTRICT:如果不包括ON UPDATE/ON DELETE,则为默认设置CASCADE:删除父级时删除子级,或在父级id更改时更新parent_id。有关详细信息,请参阅FOREIGN KEY Constraints

还有一个控制外键检查的变量。如果将其设置为0(false(,则将禁用外键检查。

SET FOREIGN_KEY_CHECKS=0;

回到您的数据库,我认为最好修改您的表结构以允许级联删除。您也可以使用ON DELETE SET NULL,然后稍后可以删除parent_id为null的任何记录。若不能修改表结构,则必须先删除子表中的记录,然后再删除父记录。

最新更新