2010-04-07 19 views
33

Sto imparando JPA e ho confusione nell'annotazione @SequenceGenerator.Java - JPA - Generatori - @SequenceGenerator

A mio parere, assegna automaticamente un valore ai campi/proprietà di identità numerici di un'entità.

Q1. Questo generatore di sequenze sfrutta la crescente capacità di generare valori numerici del database o genera il numero su di esso?

Q2. Se JPA utilizza la funzione di incremento automatico del database, funzionerà con i datastore che non dispongono di funzionalità di incremento automatico?

Q3. Se JPA genera valore numerico da solo, come fa l'implementazione JPA a sapere quale valore generare successivamente? Si consulta prima con il database per vedere quale valore è stato memorizzato per ultimo per generare il valore (last + 1)?


Q4. Si prega inoltre di fare chiarezza su sequenceName e allocationSize proprietà di annotazione @SequenceGenerator.

risposta

47

sequenceName è il nome della sequenza nel DB. Questo è il modo in cui si specifica una sequenza già esistente nel DB. Se segui questo percorso, devi specificare lo allocationSize che deve essere lo stesso valore utilizzato dalla sequenza DB come "incremento automatico".

Usage:

@GeneratedValue(generator="my_seq") 
@SequenceGenerator(name="my_seq",sequenceName="MY_SEQ", allocationSize=1) 

Se si desidera, è possibile lasciare che creare una sequenza per voi. Ma per fare questo, è necessario utilizzare SchemaGeneration per averlo creato. Per fare questo, utilizzare:

@GeneratedValue(strategy=GenerationType.SEQUENCE) 

Inoltre, è possibile utilizzare l'auto-generazione, che utilizzerà una tabella per generare gli ID. È inoltre necessario utilizzare SchemaGeneration a un certo punto quando si utilizza questa funzione, quindi è possibile creare la tabella del generatore. Per fare questo, utilizzare:

@GeneratedValue(strategy=GenerationType.AUTO) 
+3

Il provider JPA (ad esempio Hibernate) utilizzerà il valore di sequenza come base e * lo sostituirà * con l'allocazioneSize per ottenere l'ID effettivo che inserirà. Quindi se il successivo valore seq è 11 e allocationSize è 20, il prossimo ID generato sarà 220. Di solito, si desidera che gli ID seguano esattamente il valore della sequenza, quindi impostare allocationSize = l'INCREMENT BY della sequenza. Vedi anche http://stackoverflow.com/questions/5346147/hibernate-oracle-sequence-produces-large-gap –

+0

Questo non funziona per le colonne non id. –

2

Ho schema MySQL con valori di autogen. Io uso il tag strategy=GenerationType.IDENTITY e sembra funzionare bene in MySQL, immagino che dovrebbe funzionare anche la maggior parte dei motori db.

CREATE TABLE user (
    id bigint NOT NULL auto_increment, 
    name varchar(64) NOT NULL default '', 
    PRIMARY KEY (id) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

User.java:

// mark this JavaBean to be JPA scoped class 
@Entity 
@Table(name="user") 
public class User { 
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private long id; // primary key (autogen surrogate) 

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

    public long getId() { return id; } 
    public void setId(long id) { this.id = id; } 

    public String getName() { return name; } 
    public void setName(String name) { this.name=name; } 
} 
9

Io uso questa e funziona proprio

@Id 
@GeneratedValue(generator = "SEC_ODON", strategy = GenerationType.SEQUENCE) 
@SequenceGenerator(name = "SEC_ODON", sequenceName = "SO.SEC_ODON",allocationSize=1) 
@Column(name="ID_ODON", unique=true, nullable=false, precision=10, scale=0) 
public Long getIdOdon() { 
    return this.idOdon; 
} 
3

Anche se questa domanda è molto vecchio e mi sono imbattuto su di essa per i miei problemi con JPA Sequenze 2.0 e Oracle.

desidera condividere la mia ricerca su alcune delle cose -

Relazione tra @SequenceGenerator (allocationSize) di GenerationType.SEQUENZA e INCREMENTO DA nella definizione di sequenza del database

Assicurarsi @SequenceGenerator (allocationSize) è impostato su stesso valore di INCREMENTO DA nella definizione di sequenza del database per evitare problemi. Ad es. se definiamo la sequenza nel database con un valore INCREMENT BY pari a 20, impostiamo l'allocazione in SequenceGenerator anche su 20. In questo caso, il JPA non effettuerà una chiamata al database fino a quando non raggiunge il successivo segno 20 mentre incrementa ogni valore di 1 internamente. Ciò consente di salvare le chiamate al database per ottenere il numero di sequenza successivo ogni volta. L'effetto collaterale di questo è: ogni volta che l'applicazione viene ridistribuita o il server viene riavviato in mezzo, chiamerà il database per ottenere il batch successivo e vedrai i salti nei valori di sequenza. Inoltre, è necessario assicurarsi che la definizione del database e l'impostazione dell'applicazione siano sincronizzati, il che potrebbe non essere possibile in qualsiasi momento poiché entrambi sono gestiti da gruppi diversi e si può perdere rapidamente il controllo di. Se il valore del database è inferiore a allocationsize, vedrai errori del vincolo PrimaryKey dovuti a valori duplicati di Id. Se il valore del database è superiore a allocationsize, vedrai i salti nei valori di Id.

Se la sequenza di database INCREMENT BY è impostata su 1 (che è ciò che generalmente fanno gli amministratori di database), impostare allocazioni come 1 in modo che siano sincronizzate ma il database delle chiamate JPA per ottenere il numero di sequenza successivo ogni volta.

Se non si desidera la chiamata al database ogni volta, utilizzare la strategia GenerationType.IDENTITY e impostare il valore @Id in base al trigger del database. Con GenerationType.IDENTITY appena ci chiamiamo em.persist l'oggetto viene salvato a DB e un valore di ID viene assegnato per l'oggetto restituito in modo da non dover fare un em.merge o em .flush. (Questo provider può essere JPA specific..Not sicuri)

Un'altra cosa importante -

JPA 2.0 viene eseguito automaticamente ALTER SEQUENZA comando per sincronizzare l'allocationSize e INCREMENT BY in sequenza database. Come per l'usiamo un nome diverso schema (Application nome utente), piuttosto che lo schema effettivo in cui esiste la sequenza e il nome utente dell'applicazione non avrà privilegi SEQUENZA ALTER, si potrebbe vedere l'avviso di seguito nei registri -

000004c1 Runtime W CWWJP9991W: openjpa.Runtime: Avvisa: impossibile per memorizzare nella cache i valori di sequenza per la sequenza "RECORD_ID_SEQ". L'applicazione non dispone dell'autorizzazione per eseguire un comando ALTER SEQUENCE. Verificare di disporre dell'autorizzazione appropriata per eseguire un comando ALTER SEQUENCE .

Poiché l'APP non ha potuto modificare la sequenza, APP chiama ogni database per ottenere il prossimo numero di sequenza indipendentemente dal valore di @ SequenceGenerator.allocationSize. Questa potrebbe essere una conseguenza indesiderata di cui dobbiamo essere consapevoli.

Per consentire a JPA di non eseguire questo comando, impostare questo valore - in persistence.xml. Ciò garantisce che JPA non tenterà di eseguire il comando ALTER SEQUENCE. Scrive un avvertimento diverso però -

00000094 Durata W CWWJP9991W: openjpa.Runtime: Warn: L'openjpa.jdbc proprietà".DBDictionary = disableAlterSeqenceIncrementBy" è impostata su true. Ciò significa che il 'ALTER SEQUENZA ... INCREMENTO DA' SQL istruzione non verrà eseguita per la sequenza 'RECORD_ID_SEQ'. OpenJPA esegue questo comando per accertarsi che INCREMENT della sequenza valore definito nel database corrispondano al allocationSize che è definito nella sequenza dell'entità. Con questa istruzione SQL disabilitata, è la responsabilità dell'utente per garantire che dell'entità definizione sequenza corrisponda alla sequenza definita nel database.

Come indicato nell'avviso, importante qui è necessario assicurarsi che @SequenceGener ator.allocationSize e INCREMENT BY nella definizione della sequenza del database sono sincronizzati, incluso il valore predefinito di @SequenceGenerator (allocationSize) che è 50. In caso contrario causerà errori.