Search code examples
jpaeclipselinkprimary-keygenerated

GeneratedValue counter for Id resets every time that the server and client are executed


I'm working on a JavaEE application with EJB and JPA.

My Entities, are defined, for instance, like this:

@Entity
public class Utente implements Serializable {

@Id
@GeneratedValue
private int cod_utente;
private String nome_utente;
private String morada_utente;
@Temporal(TemporalType.DATE)
private GregorianCalendar dnasc_utente;
private int tel_utente;
private List<GregorianCalendar> agenda;
@OneToMany
@JoinColumn(nullable=true)
private List<Prescricao> lista_presc;

When I create entities Utente, the keys are generated sequentially starting from one. If I shut down the clients and server and execute them again, the "counter" of the key generator is reestablished. This results in an error because the application will try to create another Utente with primary key "1".

Can please someone help me solve this problem?


Solution

  • The code:

    @Id
    @GeneratedValue
    private int cod_utente;
    

    doesn't set a specific stategy to generate the values for the ID.

    It is the same as this code:

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int cod_utente;
    

    GenerationType.AUTO means that the persistence provider (in Glassfish the default persistence provider is EclipseLink) should choose an appropriate strategy for the database you are using. It looks like the persistence provider is choosing a strategy which is restarting the values after a server restart in your case.

    There are different generation strategies, you can find some detailed information in the EclipseLink Wiki.

    I guess your best bet is to use a database sequence (GenerationType.SEQUENCE) to generate the ID values.

    Example:

    Create a database sequence named GEN_SEQUENCE (if you let the persistence provider generate your tables I guess you can also let it create the sequence somehow but this example will show how to do it manually), you should look for information on how to do that in the database you are using (probably something like CREATE SEQUENCE gen_sequence;). Change your code to this:

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq_gen")
    @SequenceGenerator(name = "my_seq_gen", sequenceName = "GEN_SEQUENCE")
    private int cod_utente;
    

    You can also use the same sequence for different classes.

    Update:

    For the @SequenceGenerator you can set an allocationSize, this value is the amount of sequence values which get reserved. The default value is 50. When you have a sequence which starts at 0, the first time a value is requested from the sequence, the sequence allocates (and reserves) the values 0-49 (or 1-50). These values can be used by the persistence provider until all values have been used, then the next 50 values (50-99 or 51-100) will get allocated and reserved. The sequence remembers the current position, so that it doesn't give out the same range twice if it is used by multiple classes.

    For the value of the allocationSize you can keep the default, but this may produce gaps in the IDs. If a sequence range (e.g. 0-49) gets allocated (reserved) and only one or some of the values are used (e.g. 0, 1 and 2) the other values of this range (3-49) will get "lost" on server restart. The next time a range of values is allocated it will be 50-99, so the next ID in your table will be 50.
    Now you have the following IDs in your table: 0,1,2,50. Normally this shouldn't be a problem, but you can also set the allocationSize to a lower value or to 1 to avoid creating such gaps.

    See also: