[英]Can't create a Many-To-One relation with all-delete-orphan cascade. MySQL says a foreign key constraint fails when deleting the parent
I started using Hibernate recently and I'm still a newbie, however, the error I'm facing doesn't seem to be simple. 我最近开始使用Hibernate,但我仍然是新手,但是,我面临的错误似乎并不简单。
My current environment is: 我当前的环境是:
I'm following the "Hibernate in Action" book and did everything exactly the way it suggests. 我正在阅读《休眠中的行动》一书,并按照建议的方式进行了所有操作。
When I try to delete a parent object (UserClass) of a many-to-one relation. 当我尝试删除多对一关系的父对象(UserClass)时。 I expected that the parent object were deleted and all its child (User) too. 我希望删除父对象,并且删除其所有子对象(用户)。 However, I got java.sql.BatchUpdateException, like quoted: 但是,我得到了java.sql.BatchUpdateException,如下所示:
Exception in thread "main" org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1215)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:382)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
at netbeansproject.Main.testUserClassAndUsers(Main.java:42)
at netbeansproject.Main.main(Main.java:55)
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`lojatest`.`user`, CONSTRAINT `fk_User_UserClass1` FOREIGN KEY (`user_class_id`) REFERENCES `userclass` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION)
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2020)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1451)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 9 more
It seems to be related to MySQL Foreign Key constrants, specially regarding the "ON DELETE NO ACTION ON UPDATE NO ACTION", however, I'm not exactly an MySQL expert. 它似乎与MySQL外键约束有关,特别是关于“ ON DELETE NO ACTION ON UPDATE NO ACTION”,但是,我并不是MySQL专家。
I've found some other questions about alike situation and I still couldn't find a fix for that. 我发现了关于类似情况的其他一些问题,但仍然找不到解决方法。 Can anyone help me? 谁能帮我?
Thanks very much. 非常感谢。
Here is relevant code: 这是相关代码:
User.java: User.java:
package domain;
public class User {
private String userName;
private String password;
private Boolean blocked;
private UserClass userClass;
public User() {
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Boolean getBlocked() {
return blocked;
}
public void setBlocked(Boolean blocked) {
this.blocked = blocked;
}
public UserClass getUserClass() {
return this.userClass;
}
public void setUserClass(UserClass userClass) {
this.userClass = userClass;
}
}
User.hbm.xml: User.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="domain">
<class name="User" table="user">
<id
column="username"
name="userName"
type="string">
<generator class="assigned"/>
</id>
<property
column="password"
name="password"
not-null="true"
type="string"/>
<property column="blocked" name="blocked" type="boolean"/>
<many-to-one
name="userClass"
column="user_class_id"
class="UserClass"
not-null="true"/>
</class>
</hibernate-mapping>
UserClass.java UserClass.java
package domain;
import java.util.HashSet;
import java.util.Set;
public class UserClass {
private Long id;
private String title;
private String permissions;
private Set users = new HashSet();
public UserClass() {
}
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPermissions() {
return permissions;
}
public void setPermissions(String permissions) {
this.permissions = permissions;
}
public void setUsers(Set users) {
this.users = users;
}
public Set getUsers() {
return this.users;
}
public void addUser(User user) {
user.setUserClass(this);
this.users.add(user);
}
}
UserClass.hbm.xml: UserClass.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="domain">
<class
name="UserClass"
table="userclass">
<id
column="id"
name="id">
<generator class="native"/>
</id>
<property
column="title"
name="title"
not-null="true"
type="string"/>
<property
column="permissions"
name="permissions"
not-null="true"
type="string"/>
<set
name="users"
inverse="true"
cascade="all-delete-orphan">
<key column="user_class_id"/>
<one-to-many class="User"/>
</set>
</class>
</hibernate-mapping>
DatabaseFactory.java: DatabaseFactory.java:
package Database;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class DatabaseFactory {
private static DatabaseFactory instance = null;
private SessionFactory sessionFactory;
public static DatabaseFactory getInstance() {
if (DatabaseFactory.instance == null) {
DatabaseFactory.instance = new DatabaseFactory().init();
}
return DatabaseFactory.instance;
}
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
public Session getSession() {
return this.sessionFactory.openSession();
}
private DatabaseFactory init() {
Configuration cfg = new Configuration();
cfg.addClass(domain.UserClass.class);
cfg.addClass(domain.User.class);
cfg.setProperties(System.getProperties());
cfg.configure();
SessionFactory sessions = cfg.buildSessionFactory();
sessionFactory = cfg.configure().buildSessionFactory();
return this;
}
}
Main.java (test class): Main.java(测试类):
package netbeansproject;
import Database.DatabaseFactory;
import domain.*;
import java.util.List;
import java.util.Iterator;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class Main {
public void testUserClassAndUsers() {
System.out.println("Testing Users and UserClasses...");
Session newSession = DatabaseFactory.getInstance().getSession();
System.out.println("1 - Creating UserClasses:");
Transaction t1 = newSession.beginTransaction();
UserClass uc1 = new UserClass();
uc1.setTitle("UserClass 1");
uc1.setPermissions("XYZ");
newSession.save(uc1);
t1.commit();
System.out.println("2 - Creating Users:");
Transaction t2 = newSession.beginTransaction();
User u1 = new User();
u1.setUserName("User 1");
u1.setPassword("Password 1");
u1.setBlocked(false);
u1.setUserClass(uc1);
newSession.save(u1);
User u2 = new User();
u2.setUserName("User 2");
u2.setPassword("Password 2");
u2.setBlocked(false);
u2.setUserClass(uc1);
newSession.save(u2);
t2.commit();
System.out.println("3 - Deleting UserClass (\"UserClass 1\"):");
Transaction t3 = newSession.beginTransaction();
newSession.delete(uc1);
t3.commit();
newSession.close();
}
public static void main(String[] args) {
Main instance = new Main();
instance.testUserClassAndUsers();
}
}
SQL Script to create DB (generated by MySQL Workbench): 创建数据库的SQL脚本(由MySQL Workbench生成):
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
DROP SCHEMA IF EXISTS `LojaTest` ;
CREATE SCHEMA IF NOT EXISTS `LojaTest` ;
SHOW WARNINGS;
USE `LojaTest` ;
-- -----------------------------------------------------
-- Table `LojaTest`.`UserClass`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `LojaTest`.`UserClass` ;
SHOW WARNINGS;
CREATE TABLE IF NOT EXISTS `LojaTest`.`UserClass` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`title` VARCHAR(45) NOT NULL ,
`permissions` VARCHAR(16) NULL ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `id_UNIQUE` (`id` ASC) )
ENGINE = InnoDB;
SHOW WARNINGS;
-- -----------------------------------------------------
-- Table `LojaTest`.`User`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `LojaTest`.`User` ;
SHOW WARNINGS;
CREATE TABLE IF NOT EXISTS `LojaTest`.`User` (
`username` VARCHAR(10) NOT NULL ,
`password` VARCHAR(30) NOT NULL ,
`blocked` TINYINT(1) NOT NULL DEFAULT false ,
`user_class_id` INT UNSIGNED NOT NULL ,
PRIMARY KEY (`username`) ,
UNIQUE INDEX `id_UNIQUE` (`username` ASC)
)
ENGINE = InnoDB;
SHOW WARNINGS;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Note I'm not creating any foreign key... however, after I run my code, a foreign key is created in the User table referencing the UserClass table id. 注意我没有创建任何外键...但是,运行代码后,将在User表中创建一个外键,引用UserClass表ID。 Before this test, I've tried the same SQL script, however with the following options for the User table: 在进行此测试之前,我已经尝试了相同的SQL脚本,但是对User表使用了以下选项:
CONSTRAINT `fk_User_UserClass1`
FOREIGN KEY (`user_class_id` )
REFERENCES `LojaTest`.`UserClass` (`id` )
ON DELETE CASCADE
ON UPDATE NO ACTION
And 和
CONSTRAINT `fk_User_UserClass1`
FOREIGN KEY (`user_class_id` )
REFERENCES `LojaTest`.`UserClass` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION
None of then worked. 没有一个工作。
Thanks again. 再次感谢。
I've changed my approach and started using annotations. 我改变了方法,开始使用注释。
At first, I had the same issue, but then I read a little about JPA's EntityManager and fixed the issue. 最初,我遇到了同样的问题,但是后来我了解了一些有关JPA的EntityManager的信息,并解决了该问题。
The issue was due to removing a UserClass in the same EntityManager's context that it was created. 问题是由于在与它创建的相同EntityManager上下文中删除了UserClass。
I'm not getting back to this xml based mapping approach because it is not worthwhile (IMHO). 我不会回到这种基于xml的映射方法,因为它不值得(IMHO)。 However, I think it may be solved using more than one Hibernate session. 但是,我认为可以使用多个Hibernate会话来解决。 One to create the objects, and another to delete an object. 一种创建对象,另一种删除对象。
Hope it may help someone. 希望它可以帮助某人。 Thanks 谢谢
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.