Hibernate/H2 foreign key throwing org.h2.jdbc.JdbcSQLException

China☆狼群 提交于 2019-12-13 00:08:20

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!