web-dev-qa-db-fra.com

Différence entre @GeneratedValue et @GenericGenerator

Parfois, je les trouve ensemble, parfois seuls ... d'autres fois, ils semblent faire la même chose.

Quelle est la différence?

Voici trois exemples. Que font-ils de différent? Pourquoi ne puis-je pas utiliser uniquement @GeneratedValue pour tous?

Exemple 1

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

Exemple 2

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

Exemple 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>();
47
user1883212

Lorsque vous utilisez un ORM , il est souvent nécessaire de générer une valeur de clé primaire.

L'annotation @GeneratedValue Indique qu'une valeur pour une colonne, qui doit être annotée avec @Id, Est générée. Les éléments strategy et generator de l'annotation décrivent comment la valeur générée est obtenue.

Il y a quatre valeurs possibles pour l'élément strategy dans l'annotation @GeneratedValue: IDENTITY, AUTO, TABLE et SEQUENCE. Voir plus .

Donc, pour répondre à la deuxième partie de votre question, l'extrait de code indique que la valeur de userId sera obtenue par une séquence du base de données.

L'élément generator de l'annotation @GeneratedValue Indique le nom du générateur de clé primaire. Dans Part1 de votre question, l'extrait de code indique qu'un generator nommé increment sera utilisé pour obtenir le principal valeur clé. increment est alors défini dans la prochaine annotation @GenericGenerator. @GenericGenerator Est une annotation hibernate utilisée pour désigner un générateur personnalisé, qui peut être une classe ou un raccourci vers un générateur fourni par Hibernate. increment est un raccourci vers un générateur Hibernate qui:

génère des identificateurs de type long, short ou int qui ne sont uniques que lorsqu'un autre processus n'insère pas de données dans la même table. Ne pas utiliser dans un cluster.

Dans la troisième partie de votre question, le code utilise un générateur hilo Hibernate qui:

utilise un algorithme hi/lo pour générer efficacement des identifiants de type long, short ou int, à partir d'une table et d'une colonne (respectivement, par défaut, hibernate_unique_key et next_hi) en tant que source de valeurs hi. L'algorithme hi/lo génère des identifiants uniques pour une base de données particulière.

73
Kevin Bowersox

Pour étendre la réponse de @ kevin-bowersox.
Relations entre les stratégies de génération de clé primaire d'Hibernate et un générateur spécifique, comme spécifié dans 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);
}

Dans Hibernate 4.3, j'ai trouvé org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory classe avec 3 autres stratégies:

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

Les quinze stratégies ci-dessus, plus native, correspondent à seize stratégies de génération prises en charge dans Hibernate par défaut.

Exemple avec native:

@GeneratedValue(generator = "nativeGenerator")
@GenericGenerator(name = "nativeGenerator", strategy = "native") 
8
naXa
@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 est utilisé uniquement pour obtenir la valeur générée. Les deux arguments de la stratégie et du générateur sont utilisés pour définir comment la valeur est obtenu.
  • @GenericGenerator est utilisé pour mapper un générateur de séquence défini par l'utilisateur avec votre session d'hibernation.
  • Vous pouvez également utiliser @SequenceGenerator que j'ai commenté dans mon code. Ce n'est pas un simple générateur de séquence, mais un générateur qui travaille sur l'algorithme [~ # ~] hilo [~ # ~] . En raison de quoi vous allez trouver beaucoup de trous dans votre séquence, comme votre première valeur va commencer à 50 parce que la taille d'allocation par défaut est 50.

Il est donc préférable d’utiliser @GenericGenerator pour votre propre architecture. Mais si vous êtes obligé d'utiliser @SequenceGenerator, vous devez modifier manuellement votre séquence pour avoir deux attributs supplémentaires allocationSize = 1 et initialValue = 1 . Et pour utiliser ces attributs, vous devez ajouter apropert dans votre fichier hibernate.cfg.xml

<property name="hibernate.id.new_generator_mappings">true</property>
2
Mohd Faizan Khan