我有三个实体A,B,C。
A有很多B和C,B有很多C。我想有双向关系。
我在 Hibernate 中映射了所有这些:
@Entity
@Table(name="TABLE_A")
class A{
@Id
@GeneratedValue
private Integer a_id;
@ManyToOne
C c;
@OneToMany
List<B> bs;
}
@Entity
@Table(name="TABLE_B")
class B{
@Id
@GeneratedValue
private Integer b_id;
@ManyToOne
A a; // inverse
@ManyToOne
C c;
}
@Entity
@Table(name="TABLE_C")
class C{
@Id
@GeneratedValue
private Integer c_id;
@ManyToMany(mappedBy="c")
List<B> b; // inverse
@ManyToMany(mappedBy="c")
List<A> a; //inverse
}
我使用 SchemaUpdate 来获取在 MySQL 中生成的表。问题如下:
2012-08-24 14:57:15,437 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table TABLE_A add index FKCE3C1BF0B8CF4F47 (a_id), add constraint FKCE3C1BF0B8CF4F47 foreign key (a_id) references TABLE_A (a_id)
将约束添加到 A 到自身 - 这可能是由于 C->A 关系。映射有什么问题?
我创建了一个简单的测试文件:
@Test
public void tests() throws Exception {
Logger l = Logger.getLogger("org.hibernate.tool.hbm2ddl");
l.
setLevel(Level.DEBUG);
//Hibernate.enableCreationDebug();
A a = new A();
SessionFactory sf = configureSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
try{
session.save(a);
tx.commit();
}catch(Exception e){
tx.rollback();
throw e;
}finally{
session.close();
}
session = sf.openSession();
tx = session.beginTransaction();
try{
session.delete(a);
tx.commit();
}catch(Exception e){
tx.rollback();
throw e;
}finally{
session.close();
}
}
private static SessionFactory configureSessionFactory() throws HibernateException {
Configuration configuration = new Configuration();
String DB_USER_NAME = "kiri";
String DB_USER_PWD = "kiri";
String JDBC_CONNECTION_STRING = "jdbc:mysql://localhost/kiri";
configuration
.addAnnotatedClass(HibernateCyclicTest.A.class)
.addAnnotatedClass(HibernateCyclicTest.B.class)
.addAnnotatedClass(HibernateCyclicTest.C.class)
.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect")
.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver")
.setProperty("hibernate.connection.url", JDBC_CONNECTION_STRING)
.setProperty("hibernate.connection.username", DB_USER_NAME)
.setProperty("hibernate.connection.password", DB_USER_PWD);
// Create or update the schema to match our objects
org.hibernate.tool.hbm2ddl.SchemaUpdate schemaUpdate = new SchemaUpdate(configuration);
schemaUpdate.execute(false,/* update schema */true);
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
.buildServiceRegistry();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
这是输出:
2012-08-24 15:03:01,719 [main] INFO org.hibernate.tool.hbm2ddl.SchemaUpdate - HHH000228: Running hbm2ddl schema update
2012-08-24 15:03:01,719 [main] INFO org.hibernate.tool.hbm2ddl.SchemaUpdate - HHH000102: Fetching database metadata
2012-08-24 15:03:01,923 [main] INFO org.hibernate.tool.hbm2ddl.SchemaUpdate - HHH000396: Updating schema
2012-08-24 15:03:02,025 [main] INFO java.sql.DatabaseMetaData - HHH000262: Table not found: TABLE_A
2012-08-24 15:03:02,025 [main] INFO java.sql.DatabaseMetaData - HHH000262: Table not found: TABLE_A_TABLE_B
2012-08-24 15:03:02,026 [main] INFO java.sql.DatabaseMetaData - HHH000262: Table not found: TABLE_B
2012-08-24 15:03:02,026 [main] INFO java.sql.DatabaseMetaData - HHH000262: Table not found: TABLE_C
2012-08-24 15:03:02,027 [main] INFO java.sql.DatabaseMetaData - HHH000262: Table not found: TABLE_A
2012-08-24 15:03:02,027 [main] INFO java.sql.DatabaseMetaData - HHH000262: Table not found: TABLE_A_TABLE_B
2012-08-24 15:03:02,028 [main] INFO java.sql.DatabaseMetaData - HHH000262: Table not found: TABLE_B
2012-08-24 15:03:02,029 [main] INFO java.sql.DatabaseMetaData - HHH000262: Table not found: TABLE_C
2012-08-24 15:03:02,030 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - create table TABLE_A (a_id integer not null auto_increment, c_c_id integer, primary key (a_id)) ENGINE=InnoDB
2012-08-24 15:03:02,051 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - create table TABLE_A_TABLE_B (TABLE_A_a_id integer not null, bs_b_id integer not null, unique (bs_b_id)) ENGINE=InnoDB
2012-08-24 15:03:02,062 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - create table TABLE_B (b_id integer not null auto_increment, a_a_id integer, c_c_id integer, primary key (b_id)) ENGINE=InnoDB
2012-08-24 15:03:02,070 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - create table TABLE_C (c_id integer not null auto_increment, primary key (c_id)) ENGINE=InnoDB
2012-08-24 15:03:02,078 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table TABLE_A add index FKCE3C1BF0B8CF4F47 (a_id), add constraint FKCE3C1BF0B8CF4F47 foreign key (a_id) references TABLE_A (a_id)
2012-08-24 15:03:02,087 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table TABLE_A add index FKCE3C1BF066FAB663 (c_c_id), add constraint FKCE3C1BF066FAB663 foreign key (c_c_id) references TABLE_C (c_id)
2012-08-24 15:03:02,097 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table TABLE_A_TABLE_B add index FK64E4EEA2F8F999F6 (TABLE_A_a_id), add constraint FK64E4EEA2F8F999F6 foreign key (TABLE_A_a_id) references TABLE_A (a_id)
2012-08-24 15:03:02,107 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table TABLE_A_TABLE_B add index FK64E4EEA2C26A7AD5 (bs_b_id), add constraint FK64E4EEA2C26A7AD5 foreign key (bs_b_id) references TABLE_B (b_id)
2012-08-24 15:03:02,123 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table TABLE_B add index FKCE3C1BF1B8CFC3A7 (b_id), add constraint FKCE3C1BF1B8CFC3A7 foreign key (b_id) references TABLE_B (b_id)
2012-08-24 15:03:02,141 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table TABLE_B add index FKCE3C1BF163901C65 (a_a_id), add constraint FKCE3C1BF163901C65 foreign key (a_a_id) references TABLE_A (a_id)
2012-08-24 15:03:02,151 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaUpdate - alter table TABLE_B add index FKCE3C1BF166FAB663 (c_c_id), add constraint FKCE3C1BF166FAB663 foreign key (c_c_id) references TABLE_C (c_id)
2012-08-24 15:03:02,161 [main] INFO org.hibernate.tool.hbm2ddl.SchemaUpdate - HHH000232: Schema update complete
2012-08-24 15:03:02,583 [main] WARN org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1451, SQLState: 23000
2012-08-24 15:03:02,583 [main] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - Cannot delete or update a parent row: a foreign key constraint fails (`kiri`.`table_a`, CONSTRAINT `FKCE3C1BF0B8CF4F47` FOREIGN KEY (`a_id`) REFERENCES `TABLE_A` (`a_id`))
这是堆栈:
org.hibernate.exception.ConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`kiri`.`table_a`, CONSTRAINT `FKCE3C1BF0B8CF4F47` FOREIGN KEY (`a_id`) REFERENCES `TABLE_A` (`a_id`))
at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:74)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:49)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110)
at org.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:129)
at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81)
at $Proxy13.executeUpdate(Unknown Source)
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:56)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3134)
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3337)
at org.hibernate.action.internal.EntityDeleteAction.execute(EntityDeleteAction.java:100)
at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:362)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:354)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:280)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1214)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:403)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at com.kireego.tests.HibernateCyclicTest.tests(HibernateCyclicTest.java:59)
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.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (`kiri`.`table_a`, CONSTRAINT `FKCE3C1BF0B8CF4F47` FOREIGN KEY (`a_id`) REFERENCES `TABLE_A` (`a_id`))
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
at com.mysql.jdbc.Util.getInstance(Util.java:386)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1040)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4074)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4006)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2468)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2629)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2719)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2450)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2371)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2355)
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.hibernate.engine.jdbc.internal.proxy.AbstractStatementProxyHandler.continueInvocation(AbstractStatementProxyHandler.java:122)
... 39 more
感谢您的帮助。