注解@Id和@GeneratedValue(strategy = GenerationType.IDENTITY)的作用是什么?为什么要使用GenerationType.IDENTITY?

133
@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY)

我们为什么要使用这些注解?我想知道它是否会自动递增我的表id值。(GenerationType.IDENTITY) 除了这种类型,还有其他类型吗?当我们使用这个注解时实际上发生了什么?

public class Author extends Domain
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id") 
    private Integer id;

    @Basic(optional = false)
    @Column(name = "name") 
    private String name;

    @Column(name = "address") 
    private String address; 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "authorId")
    private List<Book>
    bookList;

    public Author()
    { 
        setServiceClassName("wawo.tutorial.service.admin.AuthorService");
    }
}

*有必要扩展Domain抽象类吗?它有什么用处?


1
http://docs.oracle.com/javaee/5/api/javax/persistence/GenerationType.html - Gustavo
5个回答

177
首先,使用注解作为我们的配置方法只是一种方便的方法,而不是复制无尽的XML配置文件。
@Id注解继承自javax.persistence.Id,表示下面的成员字段是当前实体的主键。因此,您的Hibernate和Spring框架以及您可以基于此注解进行一些反射工作。详细信息请参阅Id的javadoc文档
@GeneratedValue注解用于配置指定列(字段)的递增方式。例如,在使用Mysql时,您可以在表的定义中指定auto_increment来使其自增,并且然后使用。
@GeneratedValue(strategy = GenerationType.IDENTITY)

在Java代码中,使用

标签表示您也承认使用此数据库服务器端策略。此外,您可以更改此注释中的值以适应不同的要求。

1. 在数据库中定义序列

例如,Oracle必须使用sequence作为增量方法,假设我们在Oracle中创建一个序列:

create sequence oracle_seq;

2. 参考数据库序列

现在我们已经在数据库中有了序列,但是我们需要通过使用@SequenceGenerator来建立Java和DB之间的关系:

@SequenceGenerator(name="seq",sequenceName="oracle_seq")

sequenceName是Oracle中一个序列的真实名称,name是你想在Java中称呼它的名称。如果sequenceNamename不同,你需要指定sequenceName,否则只需使用name。通常我会忽略sequenceName以节省时间。

3. 在Java中使用序列

最后,现在是时候在Java中使用这个序列了。只需添加@GeneratedValue

@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
generator字段指的是您想要使用的序列生成器。请注意,它不是数据库中真实的序列名称,而是您在SequenceGeneratorname字段中指定的名称。

4. 完整版

因此,完整版本应该是这样的:

public class MyTable
{
    @Id
    @SequenceGenerator(name="seq",sequenceName="oracle_seq")        
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")               
    private Integer pid;
}

现在开始使用这些注解,让你的JavaWeb开发更加轻松。

2
Oracle 11.2中注释SequenceGenerator的正确语法为@SequenceGenerator(name="seq", sequenceName="ORACLE_SEQ", allocationSize=1)。否则,如果没有allocationSize参数,生成的结果非常奇怪(在我的情况下是负数)。 - hariprasad
在我的情况下,如果我不设置它,增量就是10。但这仍然是一个可选参数。 - Rugal
我的朋友说 @Id 是唯一标识符。如果你采用 Code First 方法,那么它将成为主键,否则就不同。你能解释一下上面的话吗? - Satish Patro
@PSatishPatro 正确,ID 是用于唯一标识记录的。但即使在 NoSQL 中,我们也会在表定义中始终有这样的内容。 - Rugal
1
根据Javadoc,它用于主键。 - Rugal
在使用MySQL数据库时,序列没有用处吗? - Aakash Thakur

33

简单来说,@Id:这个注解指定了实体的主键。

@GeneratedValue:这个注解用于指定要使用的主键生成策略。即指示数据库自动为此字段生成一个值。如果未指定策略,则默认使用AUTO。

GenerationType枚举定义了四种策略:

  1. Generation Type. TABLE,
  2. Generation Type. SEQUENCE,
  3. Generation Type. IDENTITY,
  4. Generation Type. AUTO。

GenerationType.SEQUENCE

使用此策略时,底层持久性提供程序必须使用数据库序列来获取实体的下一个唯一主键。

GenerationType.TABLE

使用此策略时,基础持久性提供程序必须使用数据库表来生成/保留实体的下一个唯一主键。

GenerationType.IDENTITY

这个GenerationType表示持久性提供者必须使用数据库身份列为实体分配主键。 IDENTITY列通常用于SQL Server。 这种特殊类型的列是由表本身在不使用单独序列的情况下内部填充的。 如果底层数据库不支持IDENTITY列或某些类似变体,则持久性提供者可以选择替代适当的策略。 在这些示例中,我们正在使用不支持IDENTITY列的H2数据库。

GenerationType.AUTO

这个GenerationType表示持久化提供者应该自动选择特定数据库的合适策略。这是默认的GenerationType,即如果我们只使用@GeneratedValue注释,则将使用此GenerationType的值。

参考:- https://www.logicbig.com/tutorials/java-ee-tutorial/jpa/jpa-primary-key.html


33
在对象关系映射(ORM)的环境下,每个对象都需要有一个唯一标识符。您可以使用@Id注释来指定实体的主键。 @GeneratedValue注释用于指定如何生成主键。在您的示例中,您正在使用Identity策略,该策略

表明持久性提供程序必须使用数据库标识列为实体分配主键。

还有其他策略,您可以在here中了解更多。

11
这句话的意思是:持久性提供者必须使用数据库身份列为实体分配主键。 - Lijo
3
数据库用于生成主键的一种策略是保持一个带有列(可能因情况而异)的表,只存储已分配的 id。当需要插入新行时,将生成并使用原本不存在于该表中的新 id。 - Sotirios Delimanolis
1
所以自动递增ID是吗? - Lijo
2
@404 我认为这取决于数据库。对于MySQL来说是这样的,但对于其他数据库可能会有所不同。 - Sotirios Delimanolis

5

为什么要使用这个注解?

  • 首先我想提醒大家,比如@Id这样的注解会向持久层(我将假设是hibernate)提供元数据。这些元数据很可能存储在.class文件中(但不存储在数据库中),并用于告诉hibernate如何识别、解释和管理实体。那么,为什么要使用这个注解呢?为了向持久层提供有关如何管理实体的适当信息。

为什么要使用@Id注解?

  • @Id注解是使用JPA创建实体时所需的两个强制性注解之一。另一个是@Entity@Id对我们有两个作用:

    1)表示此字段将是映射到数据库表时该类的唯一标识符

    2)存在@Id时,持久层知道该类中的所有其他字段都将映射到数据库行

为什么要使用@GeneratedValue?

  • 通过将@Id字段标记为@GeneratedValue,我们现在启用了Id生成,这意味着持久层将为我们生成一个Id值并处理自动递增。我们的应用程序可以选择4种生成策略:

    1) AUTO

    2) TABLE

    3) SEQUENCE

    4) IDENTITY

  • 如果没有指定策略,则默认为AUTO

实际上,strategy = GenerationType.IDENTITY是什么意思?

  • 当我们将生成策略指定为GenerationType.IDENTITY时,我们告诉持久化提供者(hibernate)让数据库处理id的自动递增。如果您使用postgres作为底层数据库并将策略指定为IDENTITY,则hibernate将执行以下操作:
create table users (
       id  bigserial not null,
        primary key (id)
    )

  • 注意到id的类型是bigserial,什么是bigserial?根据PostgreSQL的文档bigserial是一个大型自增整数

结论

  • 通过指定:
@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

  • 你已经告诉了基础持久层,要将id字段作为数据库中的唯一标识符。同时,使用 GenerationType.IDENTITY 告诉持久层让数据库处理自增长的id。

0
用非常简单的话来说,我们想告诉我们的数据库(DB)使用什么策略来生成主键。 现在,每个不同的行必须具有不同的主键,因此必须有一些策略告诉DB如何区分一行与另一行。 GenerationType让我们定义这种策略。
这里的@GeneratedValue(stratergy=GenerationType.IDENTITY)告诉我们的DB将主键存储在标识列中,这是SQL中默认自动递增主键生成的默认列。

目前你的回答不够清晰,请[编辑]以添加更多细节,帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

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