@GeneratedValue 和 @GenericGenerator 的区别

IT小君   2021-12-01T18:15:08

有时我发现他们在一起,有时单独……有时他们似乎也做同样的事情。

有什么不同?

下面是三个例子。他们有什么不同?为什么我不能对所有这些只使用 @GeneratedValue?

示例 1

@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment") 
Long id;

示例 2

@Id @GeneratedValue(strategy=GenerationType.SEQUENCE)
private int userId;

示例 3

@ElementCollection
@JoinTable(name="Address",
   joinColumns=@JoinColumn(name="user_id")
)
@GenericGenerator(name="hilo-gen", strategy="hilo")
@CollectionId(columns = @Column(name="Address_id"), generator = "hilo-gen", type = @Type(type="long"))
Collection<Addr> listOfAddresses = new ArrayList<Addr>();
评论(3)
IT小君

使用ORM 时,通常需要生成主键值。

@GeneratedValue注释表示一个列中的值,必须以进行注释@Id被生成。注释上的元素strategygenerator描述了如何获得生成的值。

有四个可能的值strategy的元素@GeneratedValue注释:IDENTITYAUTOTABLESEQUENCE查看更多

因此,要回答问题的第 2 部分,代码片段表明userId将通过数据库中的序列获取的值

注释generator元素@GeneratedValue表示主键生成器的名称。您问题的第 1部分中,代码片段表明将使用generator命名increment来获取主键值。 increment然后在下一个注释中定义@GenericGenerator@GenericGenerator是用于表示自定义生成器的 hibernate 注释,它可以是 Hibernate 提供的生成器的类或快捷方式。 increment是 Hibernate 生成器的快捷方式:

生成 long、short 或 int 类型的标识符,这些标识符仅在没有其他进程将数据插入同一个表时才是唯一的。不要在集群中使用。

在问题的第三部分中,代码使用了一个hiloHibernate 生成器:

给定一个表和列(默认分别为 hibernate_unique_key 和 next_hi)作为 hi 值的来源,使用 hi/lo 算法有效地生成 long、short 或 int 类型的标识符。hi/lo 算法生成仅对特定数据库唯一的标识符。

2021-12-01T18:15:08   回复
IT小君

扩展@kevin-bowersox 的回答。
Hibernate 主键生成策略和具体生成器之间的关系,分别在org.hibernate.id.IdentifierGeneratorFactory

static {
    GENERATORS.put("uuid", UUIDHexGenerator.class);     // "deprecated" for new use
    GENERATORS.put("hilo", TableHiLoGenerator.class);   // removed in Hibernate 5
    GENERATORS.put("assigned", Assigned.class);
    GENERATORS.put("identity", IdentityGenerator.class);
    GENERATORS.put("select", SelectGenerator.class);
    GENERATORS.put("sequence", SequenceGenerator.class);
    GENERATORS.put("seqhilo", SequenceHiLoGenerator.class);
    GENERATORS.put("increment", IncrementGenerator.class);
    GENERATORS.put("foreign", ForeignGenerator.class);
    GENERATORS.put("guid", GUIDGenerator.class);
    GENERATORS.put("uuid.hex", UUIDHexGenerator.class); // uuid.hex is deprecated
    GENERATORS.put("sequence-identity", SequenceIdentityGenerator.class);
}

在 Hibernate 4.3 中,我发现org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory类还有 3 个策略:

    register("uuid2", UUIDGenerator.class);
    register("enhanced-sequence", SequenceStyleGenerator.class);
    register("enhanced-table", TableGenerator.class);

以上十五种策略,加上native,是Hibernate默认支持的十六种生成策略。

示例native

@GeneratedValue(generator = "nativeGenerator")
@GenericGenerator(name = "nativeGenerator", strategy = "native")
2021-12-01T18:15:09   回复
IT小君
@Entity
@Table(name="Honey")
public class Honey implements Serializable{
    private static final long serialVersionUID = 42L;
    @Id
    //@SequenceGenerator(name="honeySequence",sequenceName="HONEY_SEQ")
    @org.hibernate.annotations.GenericGenerator(name="honeySequence", strategy = "sequence", 
    parameters = { 
            @Parameter(name="sequence", value="HONEY_SEQ") } 
    )
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="honeySequence")
    private int Id;
    private String name;
    private String taste;
  • @GeneratedValue 仅用于获取生成的值。两个参数strategygenerator用于定义如何获取值。
  • @GenericGenerator 用于将用户定义的序列生成器映射到您的休眠会话。
  • 您还可以使用我在代码中注释的 @SequenceGenerator。这不是一个简单的序列生成器,而是一个适用于HILO算法的生成器因此,您会发现序列中有很多差距,例如您的第一个值将从 50 开始,因为默认分配大小为 50。

因此最好将 @GenericGenerator 用于您自己的架构。但是,如果您必须使用 @SequenceGenerator,则必须手动编辑序列以拥有另外两个属性allocationSize=1initialValue=1要使用这些属性,您需要在hibernate.cfg.xml文件中添加 apropert

<property name="hibernate.id.new_generator_mappings">true</property>
2021-12-01T18:15:09   回复