JPA ID生成策略

标签: jpa   springboot  

JPA 为对象关系映射提供了了⼀一种基于 POJO 的持久化模型

  • 简化数据持久化代码的开发⼯工作
  • 为 Java 社区屏蔽不不同持久化 API 的差异

JPA定义了持久化的标准,而Hibernate是持久化的实现。Spring Data JPA就是在Hibernate的基础上封装实现的。

JPA提供了很多常用的注解,下面就来讲下关于主键的生成策略,主要的注解有:

@Id
@GeneratedValue(strategy, generator)
@SequenceGenerator(name, sequenceName)

JPA的通用策略生成

其生成规则由@GeneratedValue设定的。 JPA提供四种标准用法,由@GeneratedValue的源代码可以明显看出。

public @interface GeneratedValue {

    /**
     * (Optional) The primary key generation strategy
     * that the persistence provider must use to
     * generate the annotated entity primary key.
     */
    GenerationType strategy() default AUTO;

    /**
     * (Optional) The name of the primary key generator
     * to use as specified in the {@link SequenceGenerator} 
     * or {@link TableGenerator} annotation.
     * <p> Defaults to the id generator supplied by persistence provider.
     */
    String generator() default "";
}
public enum GenerationType { 

    /**
     * Indicates that the persistence provider must assign 
     * primary keys for the entity using an underlying 
     * database table to ensure uniqueness.
     */
    TABLE, 

    /**
     * Indicates that the persistence provider must assign 
     * primary keys for the entity using a database sequence.
     */
    SEQUENCE, 

    /**
     * Indicates that the persistence provider must assign 
     * primary keys for the entity using a database identity column.
     */
    IDENTITY, 

    /**
     * Indicates that the persistence provider should pick an 
     * appropriate strategy for the particular database. The 
     * <code>AUTO</code> generation strategy may expect a database 
     * resource to exist, or it may attempt to create one. A vendor 
     * may provide documentation on how to create such resources 
     * in the event that it does not support schema generation 
     * or cannot create the schema resource at runtime.
     */
    AUTO
}

JPA提供的四种标准用法为TABLESEQUENCEIDENTITYAUTO

TABLE:使用一个特定的数据库表格来保存主键。
SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。(MySQL不支持)
IDENTITY:主键由数据库自动生成(Oracle不支持这种方式)
AUTO:把主键生成策略交给持久化引擎。(如MySQL会自动对应auto increment。)

简单看下SEQUENCE的使用:

@Id  
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="sequence-generator")  
@SequenceGenerator(name="sequence-generator")  

看下@SequenceGenerator的定义:

public @interface SequenceGenerator {

    /** 
     * (Required) A unique generator name that can be referenced 
     * by one or more classes to be the generator for primary key 
     * values.
     */
    String name();

    /**
     * (Optional) The name of the database sequence object from 
     * which to obtain primary key values.
     * <p> Defaults to a provider-chosen value.
     */
    String sequenceName() default "";

    /** (Optional) The catalog of the sequence generator. 
     *
     * @since Java Persistence 2.0
     */
    String catalog() default "";

    /** (Optional) The schema of the sequence generator. 
     *
     * @since Java Persistence 2.0
     */
    String schema() default "";

    /** 
     * (Optional) The value from which the sequence object 
     * is to start generating.
     */
    int initialValue() default 1;

    /**
     * (Optional) The amount to increment by when allocating 
     * sequence numbers from the sequence.
     */
    int allocationSize() default 50;
}

在我们的应用中,一般选用@GeneratedValue(strategy=GenerationType.AUTO)这种方式,自动选择主键生成策略,以适应不同的数据库移植。

@Id  
@GeneratedValue(strategy = GenerationType.AUTO)  

如果使用HibernateJPA的实现,可以使用Hibernate对主键生成策略的扩展,通过Hibernate@GenericGenerator实现。

Hibernate主键策略生成器

Hbernate提供了多种生成器供选择,基于Annotation的方式通过@GenericGenerator实现.

Hibernate每种主键生成策略提供接口org.hibernate.id.IdentifierGenerator的实现类,如果要实现自定义的主键生成策略也必须实现此接口。

public interface IdentifierGenerator {
	/**
	 * The configuration parameter holding the entity name
	 */
	String ENTITY_NAME = "entity_name";

	/**
	 * The configuration parameter holding the JPA entity name
	 */
	String JPA_ENTITY_NAME = "jpa_entity_name";

	/**
	 * Used as a key to pass the name used as {@link GeneratedValue#generator()} to  the
	 * {@link IdentifierGenerator} as it is configured.
	 */
	String GENERATOR_NAME = "GENERATOR_NAME";

	/**
	 * Generate a new identifier.
	 *
	 * @param session The session from which the request originates
	 * @param object the entity or collection (idbag) for which the id is being generated
	 *
	 * @return a new identifier
	 *
	 * @throws HibernateException Indicates trouble generating the identifier
	 */
	Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException;
}

如何使用呢?

@Id
@GeneratedValue(generator = "hibernate-uuid")    
@GenericGenerator(name = "hibernate-uuid", strategy = "uuid") 

其中@GenericGenerator源码如下:

public @interface GenericGenerator {
	/**
	 * unique generator name.
	 */
	String name();
	/**
	 * Generator strategy either a predefined Hibernate strategy or a fully qualified class name.
	 */
	String strategy();
	/**
	 * Optional generator parameters.
	 */
	Parameter[] parameters() default {};
}
  • name属性指定生成器名称。
  • strategy属性指定具体生成器的类名。
  • parameters得到strategy指定的具体生成器所用到的参数。

Hibernate定义了很多实现好的生成器,在org.hibernate.id.factory.IdentifierGeneratorFactory的默认实现类中DefaultIdentifierGeneratorFactory

public DefaultIdentifierGeneratorFactory() {
		register( "uuid2", UUIDGenerator.class );
		register( "guid", GUIDGenerator.class );			// can be done with UUIDGenerator + strategy
		register( "uuid", UUIDHexGenerator.class );			// "deprecated" for new use
		register( "uuid.hex", UUIDHexGenerator.class ); 	// uuid.hex is deprecated
		register( "assigned", Assigned.class );
		register( "identity", IdentityGenerator.class );
		register( "select", SelectGenerator.class );
		register( "sequence", SequenceStyleGenerator.class );
		register( "seqhilo", SequenceHiLoGenerator.class );
		register( "increment", IncrementGenerator.class );
		register( "foreign", ForeignGenerator.class );
		register( "sequence-identity", SequenceIdentityGenerator.class );
		register( "enhanced-sequence", SequenceStyleGenerator.class );
		register( "enhanced-table", TableGenerator.class );
	}

关于Hibernate的主键生成策略如何选择,可以参考文章下面的引用。

参考:

Hibernate 主键生成策略选择

「真诚赞赏,手留余香」

请我喝杯咖啡?

使用微信扫描二维码完成支付

相关文章