【问题标题】:Unsuccessful: alter table XXX drop constraint YYY in Hibernate/JPA/HSQLDB standalone不成功:在 Hibernate/JPA/HSQLDB 独立中更改表 XXX 删除约束 YYY
【发布时间】:2012-08-16 18:32:40
【问题描述】:

我正在尝试使用内存中的 HSQL DB 运行一些 Hibernate/JPA 示例。我得到的错误信息如下:

13:54:21,427 ERROR SchemaExport:425 - HHH000389: Unsuccessful: alter table ReferringItem_map drop constraint FK5D4A98E0361647B8
13:54:21,427 ERROR SchemaExport:426 - user lacks privilege or object not found: PUBLIC.REFERRINGITEM_MAP
13:54:21,427 ERROR SchemaExport:425 - HHH000389: Unsuccessful: alter table ReferringItem_myCollection drop constraint FK75BA3266361647B8
13:54:21,427 ERROR SchemaExport:426 - user lacks privilege or object not found: PUBLIC.REFERRINGITEM_MYCOLLECTION
13:54:21,428 ERROR SchemaExport:425 - HHH000389: Unsuccessful: alter table ReferringItem_myList drop constraint FK6D37AA66361647B8
13:54:21,428 ERROR SchemaExport:426 - user lacks privilege or object not found: PUBLIC.REFERRINGITEM_MYLIST
13:54:21,428 ERROR SchemaExport:425 - HHH000389: Unsuccessful: alter table ReferringItem_mySet drop constraint FK3512699A361647B8
13:54:21,429 ERROR SchemaExport:426 - user lacks privilege or object not found: PUBLIC.REFERRINGITEM_MYSET

对应的类是:

@Entity
public class ReferringItem implements Serializable {

    @Id
    private long id;

    @ElementCollection
    private Collection<AnEmbeddable> myCollection
        = new ArrayList<AnEmbeddable>();

    @ElementCollection(fetch=FetchType.EAGER)
    private Set<Long> mySet = new HashSet<Long>();

    @ElementCollection(targetClass=String.class)
    private List myList = new ArrayList();

    @ElementCollection
    private Map<String,AnEmbeddable> map
        = new HashMap<String,AnEmbeddable>();

    public ReferringItem() { }

    // Setters & Getters

}

可嵌入的是:

@Embeddable
public class AnEmbeddable implements Serializable {

    private String s;

    public AnEmbeddable() { }

    public String getS() {
        return s;
    }

    public void setS(String s) {
        this.s = s;
    }

}

我的persistence.xml:

<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0">

    <persistence-unit name="JPA" transaction-type="RESOURCE_LOCAL">

        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <class>com.jverstry.jpa.AuthorizedTypes.AuthorizedTypes</class>
        <class>com.jverstry.jpa.AuthorizedTypes.OtherEntity</class>
        <class>com.jverstry.jpa.AuthorizedTypes.SomeEmbeddable</class>

        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:testdb"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
        </properties>

    </persistence-unit>

</persistence>

我在休眠 4.1.5.Final 和 HSQLDB 2.2.8。

有谁知道是什么导致了这个问题以及如何解决它?

【问题讨论】:

    标签: java hibernate jpa hsqldb in-memory


    【解决方案1】:

    您可以忽略这些错误。 create-drop 和空(内存中的情况总是如此)数据库的组合会为它尝试删除的每个数据库对象生成这些。原因是没有要删除的任何数据库对象 - DROP 语句是针对空数据库执行的。

    对于普通的永久数据库也会出现这样的错误,因为在执行 DROP 语句之前,Hibernate 没有弄清楚添加的对象是否存在于数据库中或者是新的。

    【讨论】:

    • 太好了,虽然这是我的代码中的一个问题,但我找不到。非常感谢。
    • 问题是hibernate.onjira.com/browse/HHH-7002,我在 MySQL 上看到了相同的行为,因此不仅在内存数据库中。
    • 我升级到4.3.0.Final,但仍然看到“the”错误,或者在我的情况下可能略有不同:HHH000389: Unsuccessful: alter table ... drop constraint FK_g1uebn6mqk9qiaw45vnacmyo2 if exists 和 Table "..." not found; SQL statement: ...
    • 我使用 HSQLDB 2.3.2 和 Hibernate 4.3.8,但仍然收到警告。
    • "您可以忽略这些错误。"每次你忽略一个错误,一只熊猫宝宝就会死去……#truestory
    【解决方案2】:

    这个解决方案对我有用,与给出的其他解决方案相反。显然里程有所不同。

    这是我的确切错误:

    HHH000389: Unsuccessful: alter table ... drop constraint FK_g1uebn6mqk9qiaw45vnacmyo2 if exists
    Table "..." not found; SQL statement: ...
    

    这是我的解决方案,覆盖 H2 方言:

    package com.totaalsoftware.incidentmanager;
    
    import org.hibernate.dialect.H2Dialect;
    
    /**
     * Workaround.
     * 
     * @see https://hibernate.atlassian.net/browse/hhh-7002
     * 
     */
    public class ImprovedH2Dialect extends H2Dialect {
        @Override
        public String getDropSequenceString(String sequenceName) {
            // Adding the "if exists" clause to avoid warnings
            return "drop sequence if exists " + sequenceName;
        }
    
        @Override
        public boolean dropConstraints() {
            // We don't need to drop constraints before dropping tables, that just
            // leads to error messages about missing tables when we don't have a
            // schema in the database
            return false;
        }
    }
    

    【讨论】:

    • 同样适用于 hsqldb (org.hibernate.dialect.HSQLDialect)
    • 请注意,如果您使用 jdbc:h2:mem:play;MODE=MYSQL 之类的东西,您的方言仍然是 H2 方言。
    【解决方案3】:

    上面提供的@Sander 解决方案也适用于 MYSQL。只需扩展 MySQL5InnoDBDialect,如下所示:

    import org.hibernate.dialect.MySQL5InnoDBDialect;
    
    public class ImprovedMySQLDialect extends MySQL5InnoDBDialect {
        @Override
        public String getDropSequenceString(String sequenceName) {
            // Adding the "if exists" clause to avoid warnings
            return "drop sequence if exists " + sequenceName;
        }
    
        @Override
        public boolean dropConstraints() {
            // We don't need to drop constraints before dropping tables, that just leads to error
            // messages about missing tables when we don't have a schema in the database
            return false;
        }
    }
    

    然后在您的数据源文件中更改以下行:

    dialect = org.hibernate.dialect.MySQL5InnoDBDialect
    

    到

    dialect = my.package.name.ImprovedMySQLDialect
    

    【讨论】:

    • 您在 grails 应用程序中的何处添加您的类(显然它不在任何控制器/域/视图文件夹中?
    • 我一般放在src/groovy.只要确保你使用正确的包名。
    • 谢谢我做到了。不幸的是,在尝试了所有可能的 X 小时后,我放弃了。我已经接受了这样一个事实,即每次我更改 grails 域类中的关系时,我都需要在 MySQL 中手动删除/创建我的模式
    • 遗憾的是这不起作用,它消除了错误,但导致了其他错误。根据您的数据库模式,它可能适合您,也可能不适合您。
    【解决方案4】:

    只需设置dbCreate="update",错误就会立即消失。

    见:https://stackoverflow.com/a/31257468/715608

    【讨论】:

      【解决方案5】:

      在每次使用带有 HSQLDB 和 hbm2ddl.auto=create-drop 的内存数据库的测试开始时,烦人的错误消息变得更加令人讨厌。

      对HSQLDB bug report 的回复建议使用 DROP TABLE ... CASCADE 而不是 DROP CONSTRAINT IF EXISTS。不幸的是,删除表的 HSQLDB 语法是 DROP TABLE &lt;table&gt; [IF EXISTS] [RESTRICT | CASCADE]; Hibernate Dialect 没有为方言提供一种简单的机制来在最后的 IF EXISTS 子句之后指定 CASCADE。我为这个限制写了a bug。

      但是,我能够通过创建如下自定义方言来克服这个问题:

      public class HsqlDialectReplacement extends HSQLDialect {
      
        @Override
        public String getDropTableString( String tableName ) {
          // Append CASCADE to formatted DROP TABLE string
          final String superDrop = super.getDropTableString( tableName );
          return superDrop + " cascade";
        }
      
        @Override
        public boolean dropConstraints() {
            // Do not explicitly drop constraints, use DROP TABLE ... CASCADE
            return false;
        }
      
        @Override
        public Exporter<Table> getTableExporter() {
          // Must override TableExporter because it also formulates DROP TABLE strings
          synchronized( this ) {
            if( null == overrideExporter ) {
              overrideExporter = new HsqlExporter( super.getTableExporter() );
            }
          }
      
          return overrideExporter;
        }
      
        private Exporter<Table> overrideExporter = null;
      
        private static class HsqlExporter implements Exporter<Table> {
          HsqlExporter( Exporter<Table> impl ) {
            this.impl = impl;
          }
      
          @Override
          public String[] getSqlCreateStrings( Table exportable, Metadata metadata ) {
            return impl.getSqlCreateStrings( exportable, metadata );
          }
      
          @Override
          public String[] getSqlDropStrings( Table exportable, Metadata metadata ) {
            final String[] implDrop = impl.getSqlDropStrings( exportable, metadata );
            final String[] dropStrings = new String[implDrop.length];
            for( int i=0; i<implDrop.length; ++i ) {
              dropStrings[i] = implDrop[i] + " cascade";
            }
            return dropStrings;
          }
      
          private final Exporter<Table> impl;
        };
      }
      

      【讨论】:

      • 我无法编译,不知道从哪里导入 Exporter。我的休眠版本是 4.3.8
      • 我通过使用这里使用的导入来编译它github.com/Bato/demo-jpa/blob/master/src/main/java/eu/mh/jpa/… 这似乎是这段代码的一个版本。导入 where:import org.hibernate.boot.Metadata;导入 org.hibernate.dialect.HSQLDialect;导入 org.hibernate.mapping.Table;导入 org.hibernate.tool.schema.spi.Exporter;
      【解决方案6】:

      我们在尝试在Spring 中创建一个简单的登录窗口时遇到了同样的问题。有两个表user 和role,主键id 类型为BIGINT。我们将这些 (Many-to-Many) 映射到另一个表 user_roles,其中两列 user_id 和 role_id 作为外键。

      问题是user_roles 表中的role_id 列,它属于int 类型,并且与role 的外键不兼容。当类型修改为BIGINT时,错误已被纠正。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-27
        • 1970-01-01
        • 2017-03-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-11
        相关资源
        最近更新 更多