Я недавно начал использовать Hibernate, и я все еще новичок, однако ошибка, с которой я сталкиваюсь, не кажется простой.
Моя текущая среда:
- Windows 7
- MySQL 5.1.49-community
- mysql-connector-java-5.1.13-bin.jar
- зимуют-распределение-3.6.0.Beta1
Я следую книге «Гибернация в действии» и все сделал так, как она предлагает.
Когда я пытаюсь удалить родительский объект (UserClass) отношения «многие к одному».
Я ожидал, что родительский объект был удален и все его дочерние (пользователь) тоже.
Тем не менее, я получил 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
Похоже, что это связано с константами внешнего ключа MySQL, особенно в отношении «УДАЛИТЬ НЕТ ДЕЙСТВИЯ, ОБНОВЛЕНИЕ НЕТ ДЕЙСТВИЯ», однако я не совсем эксперт MySQL.
Я нашел несколько других вопросов о подобной ситуации, и я все еще не мог найти решение для этого.
Кто-нибудь может мне помочь?
Большое спасибо.
Вот соответствующий код:
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:
<?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
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:
<?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:
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 (тестовый класс):
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-скрипт для создания БД (сгенерированный 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;
Примечание. Я не создаю никакого внешнего ключа ... однако после запуска моего кода в таблице User создается внешний ключ, ссылающийся на идентификатор таблицы UserClass.
До этого теста я пробовал тот же сценарий SQL, но со следующими параметрами для таблицы User:
CONSTRAINT `fk_User_UserClass1`
FOREIGN KEY (`user_class_id` )
REFERENCES `LojaTest`.`UserClass` (`id` )
ON DELETE CASCADE
ON UPDATE NO ACTION
И
CONSTRAINT `fk_User_UserClass1`
FOREIGN KEY (`user_class_id` )
REFERENCES `LojaTest`.`UserClass` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION
Ничего из этого не сработало.
Еще раз спасибо.