问题
I'm trying to use an H2 db for my unit testing. My actual database is MYSql, so i'm using the MYSQL dialect with H2. The problem appears to happen once the hbm files are read/loaded. The foreign keys/associations go out of whack as H2 or Hibernate try to alter the tables., or so it seems.
DB scripts:
DROP SCHEMA IF EXISTS `amr` ;
CREATE SCHEMA IF NOT EXISTS `amr`;
-- -----------------------------------------------------
-- Table `amr`.`classA`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `amr`.`classA` ;CREATE TABLE IF NOT EXISTS `amr`.`classA` (
`classA_id` INT(11) NOT NULL ,
`name` VARCHAR(56) NOT NULL ,
PRIMARY KEY (`classA_id`) );
-- -----------------------------------------------------
-- Table `amr`.`classB`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `amr`.`classB` ;CREATE TABLE IF NOT EXISTS `amr`.`classB` (
`classB_id` INT(11) NOT NULL ,
`name` VARCHAR(45) NOT NULL ,
`classA_id` INT(11) NOT NULL ,
PRIMARY KEY (`classB_id`) ,
INDEX `fk_classB_service_provider_classA1` (`classA_id` ASC) ,
CONSTRAINT `fk_classB_service_provider_classA1`
FOREIGN KEY (`classA_id` )
REFERENCES `amr`.`classA` (`classA_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION);
Exception I receive:
09-11 08:46:33 jdbc[2]: exception
org.h2.jdbc.JdbcSQLException: Column "FOREIGN" not found; SQL statement:
alter table amr.classB drop foreign key FKAF0F85CABD96B12B [42122-168]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:169)
at org.h2.message.DbException.get(DbException.java:146)
at org.h2.table.Table.getColumn(Table.java:605)
at org.h2.command.Parser.parseAlterTable(Parser.java:4874)
at org.h2.command.Parser.parseAlter(Parser.java:4315)
at org.h2.command.Parser.parsePrepared(Parser.java:306)
at org.h2.command.Parser.parse(Parser.java:279)
at org.h2.command.Parser.parse(Parser.java:251)
at org.h2.command.Parser.prepareCommand(Parser.java:217)
at org.h2.engine.Session.prepareLocal(Session.java:415)
at org.h2.engine.Session.prepareCommand(Session.java:364)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1109)
at org.h2.jdbc.JdbcStatement.executeUpdateInternal(JdbcStatement.java:121)
at org.h2.jdbc.JdbcStatement.executeUpdate(JdbcStatement.java:110)
at org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:421)
at org.hibernate.tool.hbm2ddl.SchemaExport.drop(SchemaExport.java:396)
at org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:269)
at org.hibernate.tool.hbm2ddl.SchemaExport.create(SchemaExport.java:219)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:370)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1842)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newSessionFactory(LocalSessionFactoryBean.java:860)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:779)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:188)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1514)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1452)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:567)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:103)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:1)
at org.springframework.test.context.support.DelegatingSmartContextLoader.loadContext(DelegatingSmartContextLoader.java:228)
at org.springframework.test.context.TestContext.loadApplicationContext(TestContext.java:124)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:148)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:321)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:290)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
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)
09-11 08:46:33 jdbc[2]: exception
org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "ALTER TABLE AMR.CLASSB ADD INDEX FKAF0F85CABD96B12B (CLASSA_ID),[*] ADD CONSTRAINT FKAF0F85CABD96B12B FOREIGN KEY (CLASSA_ID) REFERENCES AMR.CLASSA (ID) "; SQL statement:
alter table amr.classB add index FKAF0F85CABD96B12B (classA_id), add constraint FKAF0F85CABD96B12B foreign key (classA_id) references amr.classA (id) [42000-168]
09-11 08:46:34 jdbc[2]: exception
org.h2.jdbc.JdbcSQLException: Column "FOREIGN" not found; SQL statement:
alter table amr.classB drop foreign key FKAF0F85CABD96B12B [42122-168]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:169)
at org.h2.message.DbException.get(DbException.java:146)
at org.h2.table.Table.getColumn(Table.java:605)
at org.h2.command.Parser.parseAlterTable(Parser.java:4874)
at org.h2.command.Parser.parseAlter(Parser.java:4315)
at org.h2.command.Parser.parsePrepared(Parser.java:306)
at org.h2.command.Parser.parse(Parser.java:279)
at org.h2.command.Parser.parse(Parser.java:251)
at org.h2.command.Parser.prepareCommand(Parser.java:217)
at org.h2.engine.Session.prepareLocal(Session.java:415)
at org.h2.engine.Session.prepareCommand(Session.java:364)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1109)
at org.h2.jdbc.JdbcStatement.executeUpdateInternal(JdbcStatement.java:121)
at org.h2.jdbc.JdbcStatement.executeUpdate(JdbcStatement.java:110)
at org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:421)
at org.hibernate.tool.hbm2ddl.SchemaExport.drop(SchemaExport.java:396)
at org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:269)
at org.hibernate.tool.hbm2ddl.SchemaExport.drop(SchemaExport.java:229)
at org.hibernate.impl.SessionFactoryImpl.close(SessionFactoryImpl.java:959)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.destroy(AbstractSessionFactoryBean.java:228)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.destroy(LocalSessionFactoryBean.java:899)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:211)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:498)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:474)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:442)
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1066)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1040)
at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:958)
hbm mappings:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field">
<class name="ClassA" table="classA">
<id name="id" type="long">
<column name="id"/>
</id>
<property name="name" type="string">
<column name="name" length="56" not-null="true"/>
</property>
<set name="classBs" table="classB" inverse="true" lazy="true" fetch="select">
<key>
<column name="classA_id" not-null="true"/>
</key>
<one-to-many class="ClassB"/>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-access="field">
<class name="ClassB" table="classB">
<id name="id" type="long">
<column name="id"/>
</id>
<property name="name" type="string">
<column name="name" length="56" not-null="true"/>
</property>
<many-to-one name="classA" class="ClassA" fetch="select">
<column name="classA_id" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>
H2 URL:
jdbc:h2:~/db/amr_test;MODE=MYSQL;INIT=create schema if not exists test_db\\;runscript from 'classpath:amr_test_ddl.sql';DB_CLOSE_ON_EXIT=FALSE
-------------------EDIT/Found issue----------------------------------
After pretty much starting back from scratch and reassessing everything, found out that I improperly added the below property to my context file:
create-drop
In one of the forums that guided to my H2 context configs pointed to using it as it "drops the schema after the session closes".
So my ignorance of this property has resulted in a lesson learned.
@Thomas Mueller - thanks very much for you time and assistance with this matter.
回答1:
You have used a script that only works for MySQL.
The following script should be more cross database, according to my test it works for H2, MySQL, and PostgreSQL (I didn't test other databases). I also replaced the MySQL specific INT(11) with INT. The script assumes the schema / database amr already exists:
drop table if exists amr.classB;
drop table if exists amr.classA;
CREATE TABLE IF NOT EXISTS amr.classA (
classA_id INT(11) NOT NULL,
PRIMARY KEY (classA_id)
);
CREATE TABLE IF NOT EXISTS amr.classB (
classB_id INT(11) NOT NULL ,
name VARCHAR(45) NOT NULL ,
classA_id INT(11) NOT NULL ,
PRIMARY KEY (classB_id)
);
CREATE INDEX fk_classB_service_provider_classA1
ON amr.classA(classA_id ASC);
ALTER TABLE amr.classB
ADD CONSTRAINT fk_classB_service_provider_classA1
FOREIGN KEY (classA_id)
REFERENCES amr.classA(classA_id)
ON DELETE NO ACTION ON UPDATE NO ACTION;
Then, in the Hibernate configuration, use the H2 mode for H2.
来源:https://stackoverflow.com/questions/12371531/hibernate-h2-foreign-key-throwing-org-h2-jdbc-jdbcsqlexception