hibernate不能得到下一个序列值
我有gwt应用程序连接到后端postgres数据库,和一个Java类'判断'映射数据库中的表'判断',当我试图执行到数据库的判断,它抛出了以下错误:
Caused by: org.hibernate.exception.SQLGrammarException: could not get next sequence value ... Caused by: org.postgresql.util.PSQLException: ERROR: relation "hibernate_sequence" does not exist
我的审判class看起来像这样
@Entity @Table(name = "JUDGEMENTS") public class Judgement implements Serializable, Cloneable { private static final long serialVersionUID = -7049957706738879274L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "JUD_ID") private Long _judId; ...
我的表格判断是:
Column | Type | Modifiers -------------+-----------------------------+--------------------------------------------------------- jud_id | bigint | not null default nextval('judgements_id_seq'::regclass) rating | character varying(255) | last_update | timestamp without time zone | user_id | character varying(255) | id | integer | Indexes: "judgements_pkey" PRIMARY KEY, btree (jud_id) Foreign-key constraints: "judgements_id_fkey" FOREIGN KEY (id) REFERENCES recommendations(id) "judgements_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(user_id)
和我有一个SEQUENCE名称“judgements_id_seq”在数据库中
谁能告诉我什么是错的? 谢谢。
Hibernate的PostgreSQL方言不是很明亮。 它不知道你的每个序列的序列,并假设有一个全局的数据库范围的序列,它可以使用“hibernate_sequence”。
( 更新 :当指定GenerationType.IDENTITY
时,新的Hibernate版本可能会使用默认的每个表序列。testing你的版本,如果它适合你的话,请使用它来代替下面的代码。)
您需要更改映射以明确指定每个序列。 这是烦人的,重复的,毫无意义的。
@Entity @Table(name = "JUDGEMENTS") public class Judgement implements Serializable, Cloneable { private static final long serialVersionUID = -7049957706738879274L; @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="judgements_id_seq") @SequenceGenerator(name="judgements_id_seq", sequenceName="judgements_id_seq", allocationSize=1) @Column(name = "JUD_ID") private Long _judId; ...
allocationSize=1
是非常重要的。 如果你忽略它,Hibernate会盲目地认为序列是用INCREMENT 50
定义的,所以当它从一个序列中获得一个值时,它可以使用该值和它下面的49个值作为唯一生成的密钥。 如果你的数据库序列增加了1(默认值),那么当Hibernate尝试重新使用现有密钥时,这将导致唯一的违规。
请注意,一次获取一个密钥将导致每次插入的额外往返行程。 据我所知,Hibernate不能使用INSERT ... RETURNING
高效地返回生成的密钥,也不能使用JDBC生成的密钥接口。 如果你告诉它使用一个序列,它会调用nextval
来获取值,然后明确insert
,导致两次往返。 为了降低这个成本,你可以在有很多插入的键序列上设置一个更大的增量,记住把它设置在映射和底层的数据库序列上。 这将导致Hibernate不太经常地调用nextval
并随着caching块的密钥caching。
我相信你可以从上面看出,我不同意这里所做的Hibernatedeviseselect,至less从使用PostgreSQL的angular度来看。 他们应该使用getGeneratedKeys
或者使用INSERT ... RETURNING
和DEFAULT
作为键,让数据库处理这个问题,而不需要Hibernate在序列的名字或者明确的访问方面麻烦自己。
顺便说一句,如果你使用Hibernate和Pg,你还可能需要一个Pg的oplock触发器来允许Hibernate的乐观locking与正常的数据库locking进行安全的交互。 没有它或类似的东西你的Hibernate更新将倾向于打破通过其他常规SQL客户端所做的更改。 问我怎么知道。
我似乎记得不得不使用@GeneratedValue(strategy = GenerationType.IDENTITY)
来让Hibernate在PostgreSQL上使用'serial'列。
您需要使用策略GenerationType.IDENTITY而不是GenerationType.AUTO设置您的@GeneratedId列
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "JUD_ID") private Long _judId;
我得到了同样的错误之前,在您的数据库中键入此查询CREATE SEQUENCE hibernate_sequence START WITH 1 INCREMENT BY 1 NOCYCLE;
这对我有用,祝你好运〜
我还想添加一些关于MySQL到PostgreSQL迁移的注释:
- 在您的DDL中,在对象命名中,首选使用'_'(下划线)字符来分隔字符到骆驼事件约定。 后者在MySQL中工作正常,但在PostgreSQL中带来了很多问题。
- 在您的模型类标识字段中的@GeneratedValue注释的IDENTITY策略对于PostgreSQLDialect在hibernate3.2和更高版本中工作正常。 另外,AUTO策略是MySQLDialect的典型设置。
- 如果你使用@Table注释你的模型类,并设置一个与表名相同的字面值,确保你创build的表存储在公共模式下。
就我现在所记得的那样,希望这些提示可以让你花上几分钟的尝试和错误的手段!
我想你已经有了足够的答案,但是我得到了完全相同的错误,而我的问题是另一个错误。 我浪费了一点时间来解决这个问题。
在我的情况下,问题是在Postgres序列的所有者。 所以,如果上面的解决scheme没有解决你的问题,检查序列的所有者是否应该有权限的用户/angular色。
跟着一个例子:
CREATE SEQUENCE seq_abcd START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; ALTER TABLE public.seq_abcd OWNER TO USER_APP;
我希望这对任何人都有用。