Greenplum 中的 JPA 异常“不支持 lastval()”

Posted

技术标签:

【中文标题】Greenplum 中的 JPA 异常“不支持 lastval()”【英文标题】:JPA Exception "lastval() not supported" in Greenplum 【发布时间】:2016-05-07 12:55:29 【问题描述】:

我的代码在Postgres中运行良好,但是当我切换到Greenplum时,出现以下异常:

Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.2.v20151217-774c696): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: lastval() not supported
Error Code: 0
Call: select lastval()
Query: ValueReadQuery(name="SEQ_GEN_IDENTITY" sql="select lastval()")
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.processExceptionForCommError(DatabaseAccessor.java:1620)
    ...
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:874)
    at org.eclipse.persistence.internal.jpa.QueryImpl.performPreQueryFlush(QueryImpl.java:967)
    at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:207)
    at org.eclipse.persistence.internal.jpa.QueryImpl.getSingleResult(QueryImpl.java:521)
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getSingleResult(EJBQueryImpl.java:400)
    at module.AuthREST.login(AuthREST.java:103)
    ...
Caused by: org.postgresql.util.PSQLException: ERROR: lastval() not supported
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2157)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1886)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:555)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:417)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:302)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeSelect(DatabaseAccessor.java:1009)
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:644)

这是用户模型类:

public class User implements Serializable 

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id", nullable = false)
    private Long id;

    ...

这是 AuthREST 类中的代码:

...

@POST
@Path("login")
@Consumes("application/x-www-form-urlencoded")
public Response login(@Context HttpServletRequest request,
        @Context HttpServletResponse response,
        @FormParam("username") String username,
        @FormParam("password") String password) 

    request.login(username, password);
    ...

...

那么我应该如何避免Greenplum中的异常呢?

【问题讨论】:

您可能需要为 EclipseLink 实现一个 greenplum 方言或至少一个新的GenerationType,或者避免使用序列。虽然 GenerationType.SEQUENCE@SequenceGenerator 可能会根据实现细节起作用。 【参考方案1】:

序列在 Greenplum 中的工作方式:

主服务器有一个“序列服务器”正在运行(如果您查看进程列表,您会看到一个单独的进程) 每次段需要序列中的下一个值时,它都会连接到主节点并请求下一个值(这是开销,顺便说一句:http://engineering.pivotal.io/post/SERIAL_Datatype_Performance_in_Greenplum_Database/)

底层问题:序列服务器不会密切关注来自段服务器的请求,因此它不知道每个段的最后一个值(或多个值)。因此 lastval() 无法回答。

即使序列服务器保留分配序列值的日志:查询的工作方式,lastval() 在主服务器上执行 - 但主服务器实际上从未插入任何数据。

tl;dr:在 Greenplum 中检索序列的最后一个值是有问题的。即使支持 lastval(),返回的答案也可能不是您想要的。

【讨论】:

【参考方案2】:

使用 sql last_value 列引用您的序列表。您可以创建自己的最后一个值函数。

例子:

Select last_value from wcdl_dictionary.sq_dic_table_definition_table_id

【讨论】:

以上是关于Greenplum 中的 JPA 异常“不支持 lastval()”的主要内容,如果未能解决你的问题,请参考以下文章

ManyToOne关系中的Jpa ***异常

JPA 中的最大打开游标超出异常(使用 createNativeQuery 删除记录)

Spring Boot + 调度程序 + Spring Data JPA + Oracle 中的异常处理

Hibernate/JPA @OneToOne 返回空指针异常

JPA中的could not initialize proxy - no Session异常分析与解决

休眠查询异常:在 JPA 查询期间无法解析实体属性