JPA主键自动生成

21

我的主键实体如下所示

@GeneratedValue(strategy= GenerationType.TABLE)
private Long id;
当我运行时,我遇到了错误。
无法获取或更新下一个值;嵌套异常是 org.hibernate.exception.SQLGrammarException:无法获取或更新下一个值。
但是当我只是更改为

@GeneratedValue 
private Long id;

没有错误抛出。我想在 Oracle 数据库每个表生成唯一的主键。

3个回答

37
@GeneratedValue(strategy=GenerationType.TABLE)告诉JPA提供程序在将新创建的实体插入数据库时使用表来获取ID。当使用Hibernate作为提供程序时,这将导致一个名为 hibernate_sequences 的表,它有两列:实体名称和分配给此实体的最大标识符。在这里,似乎Hibernate无法从中获取下一个ID,但很难确定原因,因为您没有提供足够的信息。因此,请提供完整的堆栈跟踪?同时,请打开日志记录,并将 hibernate.show_sql 属性设置为 true ,并设置适当的日志级别 log4j.logger.org.hibernate.SQL = DEBUG 。如果可能,请加入该日志到您的问题中。也许只需检查是否已为Oracle配置了正确的 hibernate.dialect 。实际上,如果要使生成的数据结构与数据库类型无关,则可以让Hibernate使用 GenerationType.AUTO 来猜测最佳策略,或者使用 SEQUENCE 来强制执行。如果不是,请改用序列。编辑:回答OP有关 GenerationType.AUTO 的评论。实际上,默认值是称为 hibernate_sequence 的单个全局序列,这可能是一个问题。但是,通过下面显示的设置,您可以使用 GenerationType.AUTO ,并且仍然可以控制序列的名称,用于数据库使用序列的情况:
@Id
@GeneratedValue(strategy=GenerationType.AUTO, generator="my_entity_seq_gen")
@SequenceGenerator(name="my_entity_seq_gen", sequenceName="MY_ENTITY_SEQ")
private long id;
换句话说,你可以为每个表使用不同的序列名称,而不会失去可移植性。

2
如果我使用GenerationType.Auto,它将使用全局增量编号,这意味着所有实体都将增加相同的数字。代码运行良好,但会用尽增量编号吗? - cometta
@Pascal:如果我们提供了一个SequenceGenerator,将指定策略为AUTO是否有帮助? - Nrj
@Nrj 实际上,如果您使用 AUTO 并且数据库使用序列,则 @SequenceGenerator 将有助于控制序列的名称。但是,如果数据库不使用序列(例如 HSQLDB),它将被“忽略”。因此,与 SEQUENCE 不同,这仍然是可移植的。 - Pascal Thivent
@Pascal: 很好,谢谢,这解释清楚了。 - Nrj
谢谢您的澄清。我可以知道序列的最大数量是多少吗?它会用完序列吗? - cometta
11
默认情况下,该序列的最大数字为1E+27,即1,000,000,000,000,000,000,000,000,000。那应该足够了 :) - Pascal Thivent

10

JPA有4种自动生成策略:

  • 自动
  • Identity
  • Sequence
  • Table

对于Oracle自动生成主键的注解,你可以选择Sequence和Table。基本逻辑是首先定义一个生成器,分别使用@SequenceGenerator@TableGenerator,然后在@GeneratedValue中使用该生成器作为属性。

以下是使用Sequence策略的示例:

  @Id
  @SequenceGenerator(name="SEQ_GEN", sequenceName="SEQ_JUST_FOR_TEST", allocationSize=1)
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_GEN")
  private long id;

以下是使用表格策略的示例:

  @Id
  @TableGenerator(name="TABLE_GEN",table="T_GENERATOR", pkColumnName = "GEN_KEY", pkColumnValue = "MONITOR2012.T_JUST_FOR_TEST", valueColumnName = "GEN_VALUE", initialValue = 1, allocationSize = 1 )
  @GeneratedValue(strategy = GenerationType.TABLE, generator="TABLE_GEN")
  private long id;

如果@GeneratedValue注释中没有指定生成器,则生成选择将留给JPA实现。
如果您正在处理具有现有表的数据库,请确保在运行应用程序之前定义了数据库中的序列或表。 表生成器还需要您插入一行到表中,然后才能使@GeneratedValue注释正常工作。 这是一个关于如何在Oracle数据库中为JPA配置主键自动生成的教程。

1

身份: 根据需求自动递增,由于数据库内部轻量级锁定的高效性,但与Hibernate不太兼容,因为Hibernate采用了“事务写后刷新”策略。

序列: 预分配值以提高性能,很好地支持Hibernate的“事务写后刷新”策略。

表(序列): 可以使用一个或多个表来保存标识符序列计数器。但这意味着以牺牲写入性能换取数据库可移植性。

自动生成简要总结


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接