我的主键实体如下所示
@GeneratedValue(strategy= GenerationType.TABLE)
private Long id;
当我运行时,我遇到了错误。无法获取或更新下一个值;嵌套异常是 org.hibernate.exception.SQLGrammarException:无法获取或更新下一个值。
但是当我只是更改为 。
@GeneratedValue
private Long id;
没有错误抛出。我想在 Oracle 数据库每个表生成唯一的主键。
@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;
换句话说,你可以为每个表使用不同的序列名称,而不会失去可移植性。JPA有4种自动生成策略:
对于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;
身份: 根据需求自动递增,由于数据库内部轻量级锁定的高效性,但与Hibernate不太兼容,因为Hibernate采用了“事务写后刷新”策略。
序列: 预分配值以提高性能,很好地支持Hibernate的“事务写后刷新”策略。
表(序列): 可以使用一个或多个表来保存标识符序列计数器。但这意味着以牺牲写入性能换取数据库可移植性。
AUTO
并且数据库使用序列,则@SequenceGenerator
将有助于控制序列的名称。但是,如果数据库不使用序列(例如 HSQLDB),它将被“忽略”。因此,与SEQUENCE
不同,这仍然是可移植的。 - Pascal Thivent