JPA访问Postgresql 9.4生成序列"id"不存在报错

JPA access Postgresql 9.4 generated sequence "id" not exist error

我有一个项目需要设置与 JAVA-EE 项目一起使用的 SMS 网关。选择了 GAMMU 1.36.0。

后端数据库是 Postgresql 9.4,table 创建了收件箱和序列来保存来的 SMS。

使用创建的收件箱:

CREATE TABLE inbox (
"UpdatedInDB" timestamp(0) WITHOUT time zone NOT NULL DEFAULT     LOCALTIMESTAMP(0),
"ReceivingDateTime" timestamp(0) WITHOUT time zone NOT NULL DEFAULT LOCALTIMESTAMP(0),
"Text" text NOT NULL,
"SenderNumber" varchar(20) NOT NULL DEFAULT '',
"Coding" varchar(255) NOT NULL DEFAULT 'Default_No_Compression',
"UDH" text NOT NULL,
"SMSCNumber" varchar(20) NOT NULL DEFAULT '',
"Class" integer NOT NULL DEFAULT '-1',
"TextDecoded" text NOT NULL DEFAULT '',
"ID" serial PRIMARY KEY,
"RecipientID" text NOT NULL,
"Processed" boolean NOT NULL DEFAULT 'false',
CHECK ("Coding" IN 
  ('Default_No_Compression','Unicode_No_Compression','8bit','Default_Compression','Unicode_Compression')));

id 是一个序列号保存在:

--CREATE SEQUENCE inbox_ID_seq;

table 结构如下:

smsd-> \d inbox
                                            Table "public.inbox"
  Column       |              Type              |                           Modifiers                            
-------------------+--------------------------------+----------------------------------------------------------------
UpdatedInDB       | timestamp(0) without time zone | not null default ('now'::text)::timestamp(0) without time zone
ReceivingDateTime | timestamp(0) without time zone | not null default ('now'::text)::timestamp(0) without time zone
Text              | text                           | not null
SenderNumber      | character varying(20)          | not null default ''::character varying
Coding            | character varying(255)         | not null default 'Default_No_Compression'::character varying
UDH               | text                           | not null
SMSCNumber        | character varying(20)          | not null default ''::character varying
Class             | integer                        | not null default (-1)
TextDecoded       | text                           | not null default ''::text
ID                | integer                        | not null default nextval('"inbox_ID_seq"'::regclass)
RecipientID       | text                           | not null
Processed         | boolean                        | not null default false
Indexes:
"inbox_pkey" PRIMARY KEY, btree ("ID")
Check constraints:
"inbox_Coding_check" CHECK ("Coding"::text = ANY (ARRAY['Default_No_Compression'::character varying, 'Unicode_No_Compression'::character varying, '8bit'::character varying, 'Default_Compression'::character varying, 'Unicode_Compression'::character varying]::text[]))
Triggers:
update_timestamp BEFORE UPDATE ON inbox FOR EACH ROW EXECUTE PROCEDURE update_timestamp()

smsd-> 

请注意:列 ID 在 table 中的位置为 10。

此 table 与 GAMMU 1.36.0 配合良好,可以正常收发短信。

当我尝试开发 EJB 以将收件箱信息引入我的 Web 应用程序时。

我正在使用 JPA 2.1,实现是 EclipseLink 2.5.2。 persistence.xml 看起来像:

<persistence-unit name="SmsdJPANBPU" transaction-type="RESOURCE_LOCAL">
       <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <mapping-file>com/longz/smsd/model/SmsdInboxEntity.xml</mapping-file>
    <mapping-file>com/longz/smsd/model/SmsdOutboxEntity.xml</mapping-file>
    <mapping-file>com/longz/smsd/model/SmsdSentitemsEntity.xml</mapping-file>
    <class>com.longz.smsd.model.SmsdInboxEntity</class>
    <class>com.longz.smsd.model.SmsdOutboxEntity</class>
    <class>com.longz.smsd.model.SmsdSentitemsEntity</class>
    <properties>
        <property name="eclipselink.jdbc.url" value="jdbc:postgresql://10.0.1.100:5433/smsd"/>
        <property name="eclipselink.jdbc.driver" value="org.postgresql.Driver"/>
        <property name="eclipselink.jdbc.user" value="any"/>
        <property name="eclipselink.jdbc.password" value="any"/>
        <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
    </properties>
</persistence-unit>

JPA 实体 bean 定义:

@Entity
@Table(name = "inbox", schema = "public", catalog = "smsd")
@NamedQueries({
    /*@NamedQuery(name = "Inbox.findAll", query = "SELECT i FROM InboxEntity i ORDER BY i.id DESC"),*/
    @NamedQuery(name = "Inbox.findAll", query = "SELECT i FROM SmsdInboxEntity i order by i.id desc"),
......
public class SmsdInboxEntity implements Serializable{
......
@Id
@SequenceGenerator(name="JOB_MISFIRE_ID_GENERATOR", sequenceName="inbox_ID_seq",schema = "public", allocationSize=1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="JOB_MISFIRE_ID_GENERATOR")
@Column(name = "ID", nullable = false, insertable = true, updatable = true)
public int getId() {
    return id;
}
......
}

无状态会话 bean 为:

@Remote(InboxEntityFacadeRemote.class)
@Stateless(mappedName= "inboxEntityFacadeEJB")
public class InboxEntityFacade extends AbstractFacade<SmsdInboxEntity> implements InboxEntityFacadeRemote {
@PersistenceContext(unitName = "SmsdJPANBPU")
private EntityManager em;

@Override
protected EntityManager getEntityManager() {
    return em;
}

public InboxEntityFacade() {
    super(SmsdInboxEntity.class);
}
@Override
public List<SmsdInboxEntity> findAll(){
    Query query = em.createNamedQuery("Inbox.findAll");
    return new LinkedList<SmsdInboxEntity>(query.getResultList());
    /*return super.findAll();*/
}

我尝试使用 findall() 函数列出收件箱中的所有短信。此函数将调用命名查询语句:

@NamedQuery(name = "Inbox.findAll", query = "SELECT i FROM SmsdInboxEntity i order by i.id desc"),

测试 EJB 客户端为:

try {
        Context context = new InitialContext(properties);
        InboxEntityFacadeRemote inboxEnFaRemote = (InboxEntityFacadeRemote)context.lookup("inboxEntityFacadeEJB#com.longz.smsd.remote.InboxEntityFacadeRemote");
        System.out.println("inboxEntityFacadeEJB found.");
        List<com.longz.smsd.model.SmsdInboxEntity> todaysemails = inboxEnFaRemote.findAll();
        System.out.println("Records found: "+ todaysemails.size());
        todaysemails.stream().forEach((e) -> {
            System.out.println(e.getTextDecoded());
        });

    }catch (NamingException e) {
        e.printStackTrace();
    }

}

目前一切正常。但抛出了非常奇怪的错误:

run:
inboxEntityFacadeEJB found.
Exception in thread "main" javax.ejb.EJBException: EJB Exception: ; nested exception is: 
javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: column "id" does not exist
  Position: 8
  Error Code: 0
Call: SELECT ID, Class, Coding, Processed, ReceivingDateTime, RecipientID, SenderNumber, SMSCNumber, Text, TextDecoded, UDH, UpdatedInDB FROM smsd.public.inbox ORDER BY ID DESC
Query: ReadAllQuery(name="Inbox.findAll" referenceClass=SmsdInboxEntity sql="SELECT ID, Class, Coding, Processed, ReceivingDateTime, RecipientID, SenderNumber, SMSCNumber, Text, TextDecoded, UDH, UpdatedInDB FROM smsd.public.inbox ORDER BY ID DESC")
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.unwrapRemoteException(RemoteBusinessIntfProxy.java:117)
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:92)
at com.sun.proxy.$Proxy0.findAll(Unknown Source)
at weblogicejbclient.WeblogicInboxEJBClient.main(WeblogicInboxEJBClient.java:38)
Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: column "id" does not exist
  Position: 8
  Error Code: 0
Call: SELECT ID, Class, Coding, Processed, ReceivingDateTime, RecipientID, SenderNumber, SMSCNumber, Text, TextDecoded, UDH, UpdatedInDB FROM smsd.public.inbox ORDER BY ID DESC
Query: ReadAllQuery(name="Inbox.findAll" referenceClass=SmsdInboxEntity sql="SELECT ID, Class, Coding, Processed, ReceivingDateTime, RecipientID, SenderNumber, SMSCNumber, Text, TextDecoded, UDH, UpdatedInDB FROM smsd.public.inbox ORDER BY ID DESC")
at org.eclipse.persistence.internal.jpa.QueryImpl.getDetailedException(QueryImpl.java:378)
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:260)
at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:469)
at com.longz.smsd.ejb.InboxEntityFacade.findAll(InboxEntityFacade.java:36)
at com.longz.smsd.ejb.InboxEntityFacadeEJB_s9wt3_InboxEntityFacadeRemoteImpl.__WL_invoke(Unknown Source)
at weblogic.ejb.container.internal.SessionRemoteMethodInvoker.invoke(SessionRemoteMethodInvoker.java:34)
at com.longz.smsd.ejb.InboxEntityFacadeEJB_s9wt3_InboxEntityFacadeRemoteImpl.findAll(Unknown Source)
at com.longz.smsd.ejb.InboxEntityFacadeEJB_s9wt3_InboxEntityFacadeRemoteImpl_WLSkel.invoke(Unknown Source)
at weblogic.rmi.internal.BasicServerRef.invoke(BasicServerRef.java:701)
at weblogic.rmi.cluster.ClusterableServerRef.invoke(ClusterableServerRef.java:231)
at weblogic.rmi.internal.BasicServerRef.run(BasicServerRef.java:527)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:363)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:146)
at weblogic.rmi.internal.BasicServerRef.handleRequest(BasicServerRef.java:523)
at weblogic.rmi.internal.wls.WLSExecuteRequest.run(WLSExecuteRequest.java:118)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: column "id" does not exist
  Position: 8
  Error Code: 0
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:682)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558)
at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2002)
at org.eclipse.persistence.sessions.server.ServerSession.executeCall(ServerSession.java:570)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeSelectCall(DatasourceCallQueryMechanism.java:299)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectAllRows(DatasourceCallQueryMechanism.java:694)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRowsFromTable(ExpressionQueryMechanism.java:2738)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2691)
at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:495)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1168)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1127)
at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:403)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1215)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1751)
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258)
... 15 more
Caused by: org.postgresql.util.PSQLException: ERROR: column "id" does not exist
  Position: 8
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:304)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeSelect(DatabaseAccessor.java:1007)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:642)
... 35 more
Java Result: 1
BUILD SUCCESSFUL (total time: 1 second)

似乎 PSQL 试图在位置 8 而不是位置 10 中查找 "id" 列,实际上 "id" 列位于收件箱 table.

中的位置 10

请多多指教!赞赏!!

您的问题是区分大小写:JPA works in case insensitive mode by default (i.e. it won't quote identifiers in its queries), while PostgreSQL will convert any unquoted identifiers to lower-case(这是 PostgreSQL 尝试实现不区分大小写的方式)。但是,您在区分大小写模式下定义了 "ID" 列(注意引号)。

一个丑陋的解决方法是,您以区分大小写的方式定义您的实体:

@Column(name = "\"ID\"")

或者,您可以以不区分大小写的方式(首选)定义 table:

CREATE TABLE inbox (
    ID serial PRIMARY KEY
    -- ...
);

终于。此问题已通过使用本机 SQL 查询

修复
Query query = em.createNativeQuery("Select * from inbox",com.longz.smsd.model.SmsdInboxEntity.class);
return new LinkedList<SmsdInboxEntity>(query.getResultList());

似乎 JSQL 在这种情况下并非 100% 有效。

这篇文章可以帮助遇到同样问题的其他人。