使用Hibernate和Oracle 10g方言,我的ID是如何通过JPA生成的?

8

我有一些代码:

@Id
@SequenceGenerator(name = "SOMETHING_SEQ")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SOMETHING_SEQ")
@Column(name = "SOMETHING", nullable = false)
private Long id;

hibernate如何提供我的id?

我在数据库中看到只有一个名为“hibernate_sequence”的序列,没有其他hibernate“特殊表”。

4个回答

12

实际上,这里的SOMETHING_SEQ是您在Hibernate配置中配置的某个序列的名称。hibernate_sequence是数据库中的序列名称。在配置中,它应该类似于以下内容:

<sequence-generator name="SOMETHING_SEQ" 
    sequence-name="hibernate_sequence"
    allocation-size="<any_number_value>"/>

您可以通过使用注解完全跳过此配置。然后,您的@SequenceGenerator注解需要提供更多参数。以下是一个例子。

@SequenceGenerator(name="SOMETHING_SEQ", sequenceName="hibernate_sequence", allocationSize=10)
例如,多个实体类可能会像下面这样做:
@Entity
public class Entity1 {
  @Id
  @SequenceGenerator(name = "entity1Seq", sequenceName="ENTITY1_SEQ", allocationSize=1)
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "entity1Seq")
  @Column(name = "ID", nullable = false)
  private Long id;

  ...
  ...

}

@Entity
public class Entity2 {
  @Id
  @SequenceGenerator(name = "entity2Seq", sequenceName="ENTITY2_SEQ", allocationSize=10)
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "entity2Seq")
  @Column(name = "ID", nullable = false)
  private Long id;

  ...
  ...

}

谢谢。但在我的情况下,Hibernate是如何提供我的ID的呢?因为当我使用空值保存实体的Long ID时,它会自动插入。它是通过某些特殊表还是使用hibernate_sequence来完成的?或者其他方式? - JavaRocky
使用 hibernate-seq,当你让 Hibernate 生成它时,你不需要提供任何值。即使你提供了某个值,它也会被覆盖。 - Adeel Ansari
你是说多个实体共享同一个 Hibernate 序列吗? - JavaRocky
不一定。你可以定义其他的,看看我的附注。如果你为每个实体只定义了一个序列,那么它会使用相同的序列。 - Adeel Ansari

5
Hibernate是如何提供我的ID的?
好的,你明确告诉JPA引擎要使用@GeneratedValue注解生成标识符,并使用类型为SEQUENCE的策略,指示应使用数据库序列生成标识符。如果你想知道,序列是特定于数据库的对象(例如Oracle),可用于生成唯一整数。
我在我的数据库中看到了一个名为“hibernate_sequence”的单个序列。
你没有使用@SequenceGenerator中的sequenceName注解元素来指定要使用的数据库序列对象的名称,因此Hibernate在模式生成期间创建了默认序列对象(默认为hibernate_sequence)。要指定序列,请按以下方式执行:
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_entity_seq_gen")
@SequenceGenerator(name = "my_entity_seq_gen", sequenceName="MY_ENTITY_SEQ")
private Long id;

4
为了给序列命名,您需要在@SequenceGenerator注释中设置sequenceName
@GeneratedValue(name="gen", strategy = GeneratorType.SEQUENCE)
@SequenceGenerator(name="gen", sequenceName="Sequence_Name", allocationSize = 1)
@Id
public Long getId()
{
    // ...
}

需要注意的是,如果您正在使用现有的生成器,则您的allocationSize必须与该生成器的分配大小匹配。


0
在Oracle中,你没有像MySQL中的auto_increment类型那样的自增列。因此,要生成一个自增列,你需要使用序列(sequence)。
以下是一个示例,演示如何实现这一点。
create table test (id number, testdata varchar2(255)); 


create sequence test_seq 
start with 1 
increment by 1 
nomaxvalue; 

create trigger test_trigger
before insert on test
for each row
begin
select test_seq.nextval into :new.id from dual;
end;

你需要创建一个序列,并在每行插入之前使用触发器来添加其ID。

因此,Hibernate必须执行类似于此的操作,或者不使用触发器而使用其他方法。

insert into test values(test_seq.nextval, 'no trigger needed!');

注意:本例取自此处


谢谢。确实,Oracle没有auto_increment功能。然而,当我保存我的@Entity时,我将我的@Id字段留空。然后EntityManager会从某个地方生成一个id并插入它。当我启用控制台的SQL输出时,我就知道了这一点。那么回到我的问题,我的配置从哪里获取这个id呢? - JavaRocky
它肯定使用了序列。现在,如果它使用触发器或内联插入,请配置Hibernate以显示SQL或检查是否生成了触发器。 - Lombo
Hibernate不使用触发器,它只是在插入时获取nextval - Pascal Thivent

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