hibernate one-to-manyカスケード削除問題
既存の2つのオブジェクト:DiaryとDiaryReply
表の構造は次のとおりです.
今からDiaryを削除しようとすると、そのDiaryに関連付けられたDiaryReplyがカスケード削除されます.
次のエラーが発生しました.
org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:202)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:144)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:297)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:333)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:575)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:314)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:117)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:166)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy13.deleteDiary(Unknown Source)
at cn.edu.zjut.software.swordye.service.DiaryServiceTest.testDeleteDiary(DiaryServiceTest.java:114)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
at org.unitils.UnitilsJUnit4TestClassRunner$CustomTestMethodRunner.executeMethodBody(UnitilsJUnit4TestClassRunner.java:231)
at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66)
at org.unitils.UnitilsJUnit4TestClassRunner$CustomTestClassMethodsRunner.invokeTestMethod(UnitilsJUnit4TestClassRunner.java:155)
at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
at org.unitils.UnitilsJUnit4TestClassRunner.run(UnitilsJUnit4TestClassRunner.java:95)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`osblogdb_test/osblog_diary_reply`, CONSTRAINT `fk_r_diary_reply` FOREIGN KEY (`diary_id`) REFERENCES `osblog_diary` (`id`))
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1213)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:912)
at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:58)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:195)
... 39 more
最初はone-to-manyでcascade構成エラーだと思っていましたが、いろいろな構成を試してみても同じようにこのエラーを報告しました.ネットで検索してやっと文章の中で読んだ.元はone-to-many端の配置エラーで、*.hbm.xmlファイルは私がHibernateSynchronizerで生成したもので、このkey値には気づかなかった.この値はmanyエンド・キーが存在する属性列名、すなわちDiaryReplyが対応するテーブルのdiary_であるべきである.id.
このHibernateSynchronizerツールにバグがあるようですね!この間違いを探すのにN時間以上かかりました.のこれからこの道具を使うときは鳥に気をつけてください.
表の構造は次のとおりです.
-- ----------------------------
-- Table structure for osblog_diary_reply
-- ----------------------------
CREATE TABLE `osblog_diary_reply` (
`id` int(11) NOT NULL auto_increment,
`diary_id` int(11) NOT NULL,
`author` varchar(20) NOT NULL,
`author_url` varchar(100) default NULL,
`author_email` varchar(50) default NULL,
`owner_only` int(11) default NULL,
`content` text NOT NULL,
`create_time` datetime NOT NULL,
`last_modify_time` datetime default NULL,
`last_update_time` timestamp NULL default NULL on update CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `r_diary_reply_fk` (`diary_id`),
CONSTRAINT `fk_r_diary_reply` FOREIGN KEY (`diary_id`) REFERENCES `osblog_diary` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Table structure for osblog_diary
-- ----------------------------
CREATE TABLE `osblog_diary` (
`id` int(11) NOT NULL auto_increment,
`blog_id` varchar(32) NOT NULL,
`catalog_id` int(11) NOT NULL COMMENT ' ',
`author` varchar(20) default NULL,
`title` varchar(200) NOT NULL,
`content` text NOT NULL,
`diary_size` int(11) NOT NULL,
`view_count` int(11) NOT NULL,
`reply_count` int(11) NOT NULL,
`refer` varchar(100) default NULL COMMENT ' ',
`weather` varchar(20) default NULL,
`mood_level` smallint(6) default NULL COMMENT ' ',
`tags` varchar(100) default NULL,
`last_read_time` datetime default NULL,
`last_reply_time` datetime default NULL,
`reply_notify` smallint(6) default NULL COMMENT ' ',
`locked` smallint(6) default NULL COMMENT ' ( )',
`create_time` datetime NOT NULL,
`last_modify_time` datetime default NULL,
`last_update_time` timestamp NULL default NULL on update CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `r_catalog_diary_fk` (`catalog_id`),
KEY `r_blog_diary_fk` (`blog_id`),
CONSTRAINT `fk_r_blog_diary` FOREIGN KEY (`blog_id`) REFERENCES `osblog_site_blog` (`blog_id`),
CONSTRAINT `fk_r_catelog_diary` FOREIGN KEY (`catalog_id`) REFERENCES `osblog_diary_catalog` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*******diary.hbm.xml*******/
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="cn.edu.zjut.software.swordye.model">
<class
name="Diary"
table="osblog_diary"
>
<meta attribute="sync-DAO">false</meta>
<id
name="id"
type="integer"
column="id"
>
<generator class="native"/>
</id>
<property
name="author"
column="author"
type="string"
not-null="false"
length="20"
/>
<property
name="title"
column="title"
type="string"
not-null="true"
length="200"
/>
<property
name="content"
column="content"
type="string"
not-null="true"
/>
<property
name="diarySize"
column="diary_size"
type="integer"
not-null="true"
length="10"
/>
<property
name="viewCount"
column="view_count"
type="integer"
not-null="true"
length="10"
/>
<property
name="replyCount"
column="reply_count"
type="integer"
not-null="true"
length="10"
/>
<property
name="refer"
column="refer"
type="string"
not-null="false"
length="100"
/>
<property
name="weather"
column="weather"
type="string"
not-null="false"
length="20"
/>
<property
name="moodLevel"
column="mood_level"
type="java.lang.Short"
not-null="false"
length="5"
/>
<property
name="tags"
column="tags"
type="string"
not-null="false"
length="100"
/>
<property
name="lastReadTime"
column="last_read_time"
type="timestamp"
not-null="false"
/>
<property
name="lastReplyTime"
column="last_reply_time"
type="timestamp"
not-null="false"
/>
<property
name="replyNotify"
column="reply_notify"
type="java.lang.Short"
not-null="false"
length="5"
/>
<property
name="locked"
column="locked"
type="java.lang.Short"
not-null="false"
length="5"
/>
<property
name="createTime"
column="create_time"
type="timestamp"
not-null="true"
/>
<property
name="lastModifyTime"
column="last_modify_time"
type="timestamp"
not-null="false"
/>
<many-to-one
name="blog"
column="blog_id"
class="SiteBlog"
not-null="true"
>
</many-to-one>
<many-to-one
name="diaryCatalog"
column="catalog_id"
class="DiaryCatalog"
not-null="true"
>
</many-to-one>
<set name="diaryReplies" inverse="true" cascade="delete" lazy="true">
<key column="id"/> // , diary_id
<one-to-many class="DiaryReply"/>
</set>
</class>
</hibernate-mapping>
////*****diaryReply.hbm.xml******////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="cn.edu.zjut.software.swordye.model">
<class
name="DiaryReply"
table="osblog_diary_reply"
>
<meta attribute="sync-DAO">false</meta>
<id
name="id"
type="integer"
column="id"
>
<generator class="native"/>
</id>
<property
name="blogId"
column="blog_id"
type="string"
not-null="true"
length="32"
/>
<property
name="authorName"
column="author"
type="string"
not-null="true"
length="20"
/>
<property
name="authorUrl"
column="author_url"
type="string"
not-null="false"
length="100"
/>
<property
name="authorEmail"
column="author_email"
type="string"
not-null="false"
length="50"
/>
<property
name="ownerOnly"
column="owner_only"
type="integer"
not-null="false"
length="10"
/>
<property
name="content"
column="content"
type="string"
not-null="true"
/>
<property
name="createTime"
column="create_time"
type="timestamp"
not-null="true"
/>
<property
name="lastModifyTime"
column="last_modify_time"
type="timestamp"
not-null="false"
/>
<many-to-one
name="diary"
column="diary_id"
class="Diary"
not-null="true"
cascade="none"
>
</many-to-one>
</class>
</hibernate-mapping>
今からDiaryを削除しようとすると、そのDiaryに関連付けられたDiaryReplyがカスケード削除されます.
public void deleteDiary(Diary diary) {
getSession().delete(diary);
}
次のエラーが発生しました.
org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:202)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:144)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:297)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:333)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:575)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:662)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:632)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:314)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:117)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:166)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy13.deleteDiary(Unknown Source)
at cn.edu.zjut.software.swordye.service.DiaryServiceTest.testDeleteDiary(DiaryServiceTest.java:114)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
at org.unitils.UnitilsJUnit4TestClassRunner$CustomTestMethodRunner.executeMethodBody(UnitilsJUnit4TestClassRunner.java:231)
at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66)
at org.unitils.UnitilsJUnit4TestClassRunner$CustomTestClassMethodsRunner.invokeTestMethod(UnitilsJUnit4TestClassRunner.java:155)
at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
at org.unitils.UnitilsJUnit4TestClassRunner.run(UnitilsJUnit4TestClassRunner.java:95)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.sql.BatchUpdateException: Cannot delete or update a parent row: a foreign key constraint fails (`osblogdb_test/osblog_diary_reply`, CONSTRAINT `fk_r_diary_reply` FOREIGN KEY (`diary_id`) REFERENCES `osblog_diary` (`id`))
at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1213)
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:912)
at org.apache.commons.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:58)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:195)
... 39 more
最初はone-to-manyでcascade構成エラーだと思っていましたが、いろいろな構成を試してみても同じようにこのエラーを報告しました.ネットで検索してやっと文章の中で読んだ.元はone-to-many端の
このHibernateSynchronizerツールにバグがあるようですね!この間違いを探すのにN時間以上かかりました.のこれからこの道具を使うときは鳥に気をつけてください.