mysql - 无法删除或更新父行:更新外键时外键约束失败
问题描述
我有一个实体成员
public class Member implements Serializable {
@Id
@Column(nullable = false, updatable = true)
private String email;
private String name;
private String surname;
private String password;
private String phone;
private String url_image;
// posts the user has made
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private Collection<Post> posts = new ArrayList<>();
// load the roles everytime we load a user
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Collection<Role> roles = new ArrayList<>();
// foreign key relationships
@OneToMany(cascade = CascadeType.ALL, mappedBy = "member", orphanRemoval = true)
private Collection<Likes> like;
// constructor, getters, setters
}
实体角色
public class Role {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
}
和一个实体 Post:
public class Post implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String text;
private Date date;
private String post_name;
private String post_surname;
}
实体 Member 与 Post 和 Roles 具有 OneToMany 关系,我希望当成员的电子邮件更新时,其他实体上的相应记录也具有更新的外键。此外,还有另一种情况,称为 Likes 的实体:
public class Likes implements Serializable {
@Id
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "post_id", referencedColumnName = "id")
private Post post_id;
@Id
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "email", referencedColumnName = "email")
private Member member;
}
其中关系由成员映射到喜欢。在我在 MyQSL 上运行更新查询的所有情况下,我都会收到错误消息
Cannot delete or update a parent row: a foreign key constraint fails(`members`.`member_posts`, CONSTRAINT `FKbd5r2qwucjyiwbv538j3edjad` FOREIGN KEY (`member_email`) REFERENCES `member` (`email`))
要么来自由 Member 和 Post 的关系构成的 member_posts 表,要么来自由 Member 和 Roles 的关系或 Likes 表构成的 member_roles 表。任何人都知道我在这里搞砸了什么,因为我真的无法弄清楚。
解决方案
如果我对您的理解正确,您已经使用用户的电子邮件地址作为从子表到父表的外键引用。现在您需要更新电子邮件地址。
外键是数据完整性约束。它们的存在是为了确保子行始终具有对父行的有效引用。因此,您无法更改父列,因为子列将不再具有有效引用,并且您无法更改子列,因为它将指向不存在的父列
(可以将子电子邮件地址设置为现有但不正确的父电子邮件,因此可以应对在父表上设置唯一索引并首先更新父表。然后父更新将由于重复而失败。)
幸运的是,您可以通过在执行更新时禁用外键约束来解决所有这些问题:
SET FOREIGN_KEY_CHECKS = 0;
当然,一旦更新完成,您需要再次启用检查:
SET FOREIGN_KEY_CHECKS = 1;
但是如果出现问题怎么办?
如果由于某种原因更新失败并且外键检查被禁用,您可以让您的数据库处于未知状态。为了解决这个问题,将整个更新包装在一个事务中:
在伪代码中:
SET FOREIGN_KEY_CHECKS = 0;
START TRANSACTION;
UPDATE parentTable set email = 'newEmail@example.com' where email = 'oldEmail@example.com';
UPDATE childTable set email = 'newEmail@example.com' where email = 'oldEmail@example.com';
IF (No error hos occurred)
COMMIT
ELSE
ROLLBACK
ENDIF
SET FOREIGN_KEY_CHECKS = 1;
这就是 MySQL 的解决方案。使用可变数据作为外键约束可能是一个糟糕的选择。我会考虑用包含父 ID 的列替换电子邮件外键并在其上设置外键约束。这不应该改变,然后可以随意更新电子邮件地址。
不幸的是,春天不是我的菜。这是解决方案,但您必须自己实施。
推荐阅读
- vue.js - 错误:在 /Users/name/Desktop/blognewtonmcvue/store 中找不到 ESLint 配置
- php - laravel 迭代在父级上添加量
- java - LeetCode 除以两个整数 - 负数的重复指数搜索解决方案
- node.js - 5分钟后在Heroku中强制关闭nodemailer连接
- concrete5 - $_FILES、$_POST、$_SERVER 的具体方法
- java - Java:使用数组中的数据启动函数的线程
- java - Java RMI 问题:无法解决线程“主”java.rmi.NotBoundException 中的异常:服务器
- java - 如何使用 actionListener 更改 JButton 的颜色
- c# - 如何使用 LINQ 将单元格值从 DataGridView 传递到 ListBox
- linux - Azure:无法将自定义数据传递或执行到 VM