【问题标题】:JPA with Hibernate 3.6.8.Final, PostgreSQL 9.1, SQLGrammarException - configuration issue? Weird SQL statementJPA with Hibernate 3.6.8.Final, PostgreSQL 9.1, SQLGrammarException - 配置问题?奇怪的 SQL 语句
【发布时间】:2011-11-14 10:25:01
【问题描述】:

编辑已解决 正确的。我发现了让我感到困惑的事情。 我使用 pgadmin 创建表和其他数据库内部,现在检查:如果名称中的至少一个字母(表名、列名、pk 名等)是大写的,那么 pgadmin 在 SQL 创建脚本中使用它因为它是使用双引号,所以 PostgreSQL 解释它所写的名称。如果运行以下脚本:

CREATE TABLE SAMPLE
(
  ID integer NOT NULL,
  TITLE character varying(100) NOT NULL,
  CONSTRAINT SAMPLE_ID_PK PRIMARY KEY (ID)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE SAMPLE
  OWNER TO postgres;_

它以小写形式创建所有内容,并且原始 Sample.java 版本工作正常。


这里有什么问题?这个问题是 PostgreSQL 9.1 或一般 PostgreSQL 特有的,还是缺少某些休眠配置?

persistence.xml:

<persistence-unit name="com.sample.persistence.jpa" transaction-type="RESOURCE_LOCAL">
    <class>com.sample.persistence.Sample</class>
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
        <property name="hibernate.connection.url" value="jdbc:postgresql:sample"/>
        <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
        <property name="hibernate.connection.username" value="postgres"/>
        <property name="hibernate.connection.password" value="postgres"/>
        <property name="hibernate.show_sql" value="true"/>
        <property name="hibernate.format_sql" value="true"/>
        <property name="hbm2ddl.auto" value="update"/>
    </properties>
</persistence-unit>

Sample.java

@Entity
@Table(name = "SAMPLE")
public class Sample {

    @Id
    @Column(name = "ID")
    private long id;

    @Column(name = "TITLE")
    private String title;

    public String getTitle() {
        return title;
    }
}

PersistenceMain.java:

public class PersistenceMain {


    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.sample.persistence.jpa");
        EntityManager em = emf.createEntityManager();

        Sample sample = em.find(Sample.class, 1l);

        System.out.println("Sample Title: " + sample.getTitle());

        em.close();

        emf.close();
    }
}

例外:

...
Hibernate: 
    select
        sample0_.ID as ID0_0_,
        sample0_.TITLE as TITLE0_0_ 
    from
        SAMPLE sample0_ 
    where
        sample0_.ID=?
Exception in thread "main" javax.persistence.PersistenceException:     org.hibernate.exception.SQLGrammarException: could not load an entity:   [com.sample.persistence.Sample#1]
 ...
Caused by: org.postgresql.util.PSQLException: ERROR: relation "sample" does not exist
 ...

显然,上面的这条SQL语句:

select
    sample0_.ID as ID0_0_,
    sample0_.TITLE as TITLE0_0_ 
from
    SAMPLE sample0_ 
where
    sample0_.ID=?

未从 PostgreSQL 本身(来自 pgadmin)成功执行。

但是,如果我将 Sample.java 更改为:

@Entity
@Table(name = "\"SAMPLE\"")
public class Sample {

    @Id
    @Column(name = "\"ID\"")
    private long id;

    @Column(name = "\"TITLE\"")
    private String title;

    public String getTitle() {
        return title;
    }
}

这很奇怪,它有效。

Hibernate: 
    select
        sample0_."ID" as ID1_0_0_,
        sample0_."TITLE" as TITLE2_0_0_ 
    from
        "SAMPLE" sample0_ 
    where
        sample0_."ID"=?
Sample Title: Sample

hibernate.dialect 在这里没用,还是不能在 PostgreSQL 9.1 上正常工作? 另外,如果列名与字段相同,我不想输入列名,但如果是大写,也可以吗?

谢谢。

【问题讨论】:

  • 如果你删除了休眠方言相关的属性——它会起作用吗? AFAIR @Entity(\""..."\") 构造是强制 JPA 提供程序使用提供的确切值(即使用表名的确切大小写)。不知道为什么在你的情况下它会变魔术。
  • 我试过不带方言,原来的Sample.java不行,修改后可以,也试过用MySQL方言代替PostgreSQL,只是期望看到警告或错误,结果是一样的,似乎 a) 方言被忽略 b) 在构造 SQL 查询时不使用方言,但可能仅用于供应商特定的行为,例如分页。
  • 如果您尝试使用 JPA 属性进行 JDBC 连接 (vogella.de/articles/JavaPersistenceAPI/…) 并删除方言和休眠相关的属性会怎样?您的数据库中的确切表名是什么?
  • PostgreSQL 脚本:CREATE TABLE "SAMPLE" ("ID" integer NOT NULL, "TITLE" character varying(100) NOT NULL, CONSTRAINT "SAMPLE_ID_PK" PRIMARY KEY ("ID" )与(OIDS=FALSE);将表“样本”所有者更改为 postgres;

标签: hibernate jpa postgresql-9.1


【解决方案1】:

@Table("\"...\"") 构造是强制 JPA 提供程序使用您提供的确切值(即使用表名的确切大小写)。

此外,它在 PostgreSQL 世界中也是类似的。如果您调用 CREATE TABLE 并在引号中指定表名,那么它将创建具有您指定的确切名称的表(不仅是大小写,还有语义 - 这样您甚至可以创建一个名为 TABLE 的表):

CREATE TABLE "TeSt" ( id int PRIMARY KEY NOT NULL )

将生成表 TeSt8

CREATE TABLE TeSt2 ( id int PRIMARY KEY NOT NULL )

将生成表 test2

因此,要查询“TeSt”表,您需要执行SELECT * FROM "TeSt"不是 SELECT * FROM TeSt)。

因此,如果您使用CREATE TABLE "SAMPLE" 创建表,则需要指定@Table(name="\"SAMPLE\"") 才能使其正常工作。

【讨论】:

  • 在我的问题标题中添加了解释。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多