JPA Mini Book – First Steps and detailed concepts

Id Generation: Definition, using Identity or Sequence

As said in page 5, every entity must have an id. JPA has the option to automatically generate the entity id.

There are three ways to use the automatically id generation:

  • Identity
  • Sequence
  • TableGenerator

We must have in mind that every database has its own id generation approach. Oracle and Postgres databases use the Sequence approach, SqlServer and MySQL use the Identity approach. It is not possible to use an id generation approach in a server when the server does not support it.

The allowed types for an id attribute are: byte/Byte, int/Integer, short/Short, long/Long, char/Character, String, BigInteger, java.util.Date e java.sql.Date.

Identity

This is the simplest id generation approach. Just annotate the id field like bellow:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Person {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	private String name;

	public String getName() {
		return name;
	}

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

The database will control the ID generation, the JPA will not act in any moment. The entity requires to be persisted, and after the transaction commit, a query in the database will be fired to get the generated id for the persisted entity. It could lead to a small loss of performance, but not alarming.

This approach of id generation does not allow allocating ids in memory. We will see next what this ids allocation means.

Sequence

The Sequence approach can be configured like below:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;

@Entity
@SequenceGenerator(name = Car.CAR_SEQUENCE_NAME, sequenceName = Car.CAR_SEQUENCE_NAME, initialValue = 10, allocationSize = 53)
public class Car {

	public static final String CAR_SEQUENCE_NAME = "CAR_SEQUENCE_ID";

	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = CAR_SEQUENCE_NAME)
	private int id;

	private String name;

	public String getName() {
		return name;
	}

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

About the code above:

  • The @SequenceGenerator annotation will define that there will be a  sequence in the database with the specified name (sequenceName attribute). The same sequence could be shared between entities but is not a good idea. If we use the Car sequence in the House entity, the id values in the tables would not be sequential; when the first car is persisted the id would be 1, if other car is persisted the id would be 2; when the first house is persisted its id would be 3, this will happen if the House entity uses the same sequence as the Car entity.
  • The attribute name = Car.CAR_SEQUENCE_NAME define the name of the sequence inside the application. In any Entity that will use the same sequence it will not be necessary to declare the Sequence again, just use the same sequence name again. That is why there is a static attribute with this value.
  • The value sequenceName = Car.CAR_SEQUENCE_NAME reflects the database sequence name.
  • The initialValue = 10 defines the first id value of the table. A developer must be cautious with this configuration; if after inserting the first value the application is restarted, the JPA will try to insert a new entity with the same value define in the initialValue. An error message will be displayed indicating that the id is already in use.
  • allocationSize = 53 means the amount of ids that the JPA will have stored in cache. Works like this: when the application is started the JPA will allocate in the memory the specified value and will share these values to each new persisted entity. In the code above, the ids would go from the initialValue + 53. When the allocated ids numbers finish the JPA will go the database when allocate more + 53 ids in memory. This act of allocating ids into the memory it is a good approach to optimize the server memory, the JPA will not need to go to the database to get the created id like the @Identity approach.
  • The @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = CAR_SEQUENCE_NAME) annotation defines that the generation type as SEQUENCE and the name of the generator.

50 thoughts on “JPA Mini Book – First Steps and detailed concepts

  1. I copied and pasted and generated a PDF file – let me know how to send it to you – so that you can upload
    Thanks for the wonderful information and sharing your knowledge

  2. Olá. Há realmente necessidade de colocar @IdClass na Entidade?

    Usando apenas 3 @Id aqui na minha Entidade, o hibernate criou sozinho a chave composta. Qual seria o problema recorrente de fazer isso em uma @IdClass?

    • Davi, boa tarde.

      Infelizmente não sei falar se pode haver algum problema em sua abordagem.

      Nos dois livros que li que abordavam sobre JPA ambos falavam para utilizar o IdClass.

      Obrigado pela visita.

  3. Cara, como que faço pra salvar a entidade que tem N-N com atributos? Tudo quanto é coisa que eu faço da erro de detached…

    Eis minha ultima tentativa:

    public String editar(){
    prospecto = prospectoService.buscarProspectoComAcoes(prospecto.getId());

    log.debug(“Antes: “+prospecto.getProspectoCampos().size());

    List prospectoCampos = new ArrayList();

    for(ProspectoHelper hp : ProspectoHelper.extrairDadoDoModelo(dynaFormModelUniao)){
    ProspectoCampo pc = new ProspectoCampo();
    pc.setCampo(campoService.findOne(hp.getPropertyFilter().getCampo().getId()));
    pc.setValor(hp.getPropertyFilter().getValue().toString());
    pc.setProspecto(prospecto);
    prospectoCampos.add(pc);
    }

    prospecto.setProspectoCampos(prospectoCampos);

    log.debug(“Depois: “+prospecto.getProspectoCampos().size());

    prospecto.adicionarAcao(acaoSelecionada);

    try{
    prospectoService.save(prospecto);
    }catch(Exception e){
    log.error(“Erro ao editar Prospecto!”, e);
    messageUtil.sendErrorMessageToUser(“global.error”, “global.insert.error”, e.getMessage());
    return null;
    }

    return getRadarPath();
    }

    Abraços

    • Marco, boa tarde.

      Repare que você não tem uma transação única, por isso que ao buscar o objeto de um serviço e salvar em outro ele apresenta essa mensagem.

      Leia a parte sobre esse erro aqui deste post, ele explica direitinho o que está acontecendo.

      Obrigado pela visita.

  4. i am a self-study for java.
    I have view Your tutorials that are very very simple to understand.,
    I have a request for you.

    From the mini book for JPA and the tutorial for JSF , i have noted that into the Entity class and the managedbeans with scoped Session that implements Serializable you put a field :private static final long serialVersionUID = 343L;

    Whi into all class that implements Serializable have a field static final of type Long?
    private static final long serialVersionUID = 343L;
    or
    private static final long serialVersionUID = 1L

    ??????????????

    whi it is static final long ?
    please explique me ……..

    tank you
    Mauro

  5. Thanks for taking the time to write out this tutorial.

    A few suggestions to improve this article.
    – Firstly its a good practice to make sure all entity classes implement the java.io.Serializable interface.

    – When setting the @OneToMany annotation, it is important to talk about the CascadeType options for easier creation/updation of entities. An example of code for insert/update/delete of the entities with and without the CascadeType option will demonstrate the difference in use.

    – The mappedBy value in the cellular class = cellular. What this defines should be explained. This actually refers to the instance variable cellular on the Call object. Since the names are all kept the same most readers will be confused on the name mapping. They may think it refers to the classname when in fact it has nothing to do with the class name.
    I find it useful to actually change the names to demonstrate the actual relationships. So calling cellular, cellularRef on the Call object would make this point more obvious.

    • Hello Kapil,

      1) I just see implementing java.io.Serializable as good practice if you have a multi clustered environment or remove EJB (or anything related to serialization). Do you have any article that talk about that always implementing java.io.Serializable is a good practive?
      2) In this article there is a page that talks about Cascade. [=
      3) Thanks for the mappedBy tip. I will edit it later. [=

      Thanks for passing by! =D

      • When you write code you do not know the target configuration for deployment especially for packaged apps. If you do not implement Serializable and ship your bundle off to a client and they are running a multi clustered environment, guess what will happen?

        • Hello Kapil,

          I do know some seniors Java developers that use JPA and never needed to work with clustered environments.

          Thinking about OO, if a class will never be used in an clustered environment why would it be considered a good practice to add this Interface?

          You thoughts will remain here to be used as an alert to other developers.

          Thanks for passing by! [=

          • Well its good to have differences in opinion :).

            When I write software I can never tell if it is going to be used in a clustered environment or not. All the enterprises i have worked for have had nothing but multi clustered (Cluster of clusters) environments. I rarely write software that would work only on a single node. Unless of course its a quick Proof Of concept.

          • Indeed.

            I always will have the idea that a code that does not follow a good practice will run in every environment.

            In your case, is not good practice but a requirement. Where I live I know a lot of developers that never worked with clustered environment.

            Thanks for passing by.

  6. I outlined the reason why you would implement the interface in my previous comment.
    I can try and explain once again.
    As an example let’s say you are building a Human Resources application that you intend to sell to clients. You are using JPA and do not implement the Serializable interface. One of the clients you sell to is a very large corporation that has a clustered environment. When they buy your application and try to deploy it on their environment it will start throwing serialization errors.
    Does that make sense?

    • Hello Kapil,

      I do not know what is reality of software programming where you live, but I know several developers that never built a software to be sold.

      A developer must understand this: If your software is to be used in a non clustered environment, you will not need to add the interface. If your software is for a clustered environment the interface is not a good practice, but a requirement. That is the difference.

      And if you are building a software to be sold, only by applying the interface will not make your software ready for a clustered environment. A clustered environment is a Requirement that should be specified in the beginning.

      I do respect your opinion, but I do not agree with it. [=

      Thanks for passing by.

  7. Couple of points of interest here :

    1. Usually have the owner of the ManyToMany relationship be the entity that has the less rows when navigating the right side of the join.
    So for e.g. If 1 student can have many courses and many students can have one course we have a many to many relationship between students and courses. In such a model (practically), when navigating from a student record to courses you will have fewer records than from navigating courses to student. In such a case, it makes more sense to define the owner of the relationship be student and not courses. The reason I am saying this when you have a new student in the system its more optimal from a SQL standpoint to navigate from Student to Courses and add the new course. If you had to navigate the other way you will potentially have many more records which means more objects loaded to represent the relationship which means a poorer performing application.

    2. Also in your example you do not need to set both of these
    person.setDog(dogs);
    dog.setPersons(persons);

    just person.setDog(dogs) should work.

    • Hello Kapil,

      1. Sometimes you do not know which entity will have less rows, that I think that the books that I read do not put who should be the owner like you did. But I did like your point of view.

      2. To work like that depends on your implementation. The JPA Pro 2 book makes it clear that passing to only one side the reference the other side will see it.

      Thanks for passing by.

      PS.: Sorry for taking too long to answer you.

    • I do not forgot it, but sometimes an implementation does. =P

      Take the JPA implementation by example, you can have some methods behaving different in each implementation.

      Sometimes The spec says only what a method can or cannot do, allowing it to behave and to have an final destination chosen by it own.

      Thanks for passing by.

  8. Yes and this is perfectly acceptable. You change behavior at deployment time w/o having to recompile code.
    However adding an interface to the codebase will require a recompile. See the difference?
    My point is it does not hurt to put in the interface. It costs nothing but makes your app scale up in a J2EE deployment. Even scaling vertically where the Views & Controller runs in one JVM (Servlets/JSP’s) and the Model (Entities) run in another JVM you will not be able to pass entities to the controller because they do not serialize.

    • 1) If you think by OO, a class have no reason to know a Interface that it will not use it.
      2) A team with developers without experience will not know why the serializable is there (I saw that happing a lot of times), and will start adding it to several other classes thinking that it will solve some error.

      I sorry, but no, I do not see it as good practice. If it is not a requirement, it should not be present.

  9. Hi,
    I have the below scenario. Can I map this relationship in JPA xml if so can you please tell me how to do. Thank you so much.
    We have tables users (userId), organizations(orgId), roles(roleId) and joining tables are users_orgrole_map (userId, orgRoleId) and org_roles_map (orgRoleId, OrgId, roleId). The User Object will have Set of Organizations and Organization Object have set of Roles. (ie User can have different roles in different Organization. UserA belong to OrgA with RoleA permission and UserA belong to OrgB with RoleB permission.)

    • Hello Harishyam,

      Check in this post the page “ManyToMany with extra fields”.

      Thanks for passing by, I am sorry for the late reply. I was very busy this last month.

  10. Hi~ thanks for the great tutorial. It’s very helpful for beginners to understand how composite PK works. I have a question though. How can I create query using only one of the key.

    For instance, I want to find out the cars of a particular CarID.brand. How does it work for your example code? thanks.

    • Hello Dean, how are you?

      You could create the PK key for the query e pass only the value. Something like:
      MyKey key = new MyKey();
      key.setValueA(onlyValueYouHave);
      // do the query

      Thanks for passing by.

  11. Hi, how can i in the example above get all the persons for specific dogId or vice versa using entity manager? thanks

  12. Hi,

    Great post!!
    Could you add the column “cellular_id” to the table “Person”? This makes it clearer. Otherwise, I was scrathcing my head where “cellular_id” is.

    Thanks!

  13. Hello uaihebert,

    Thank you for explaining @TableGenerator. I am a bit confused by how to use initialValue. If I specify an initialValue that is already in use, will the application attempt to overwrite entities in the database? If so, how can I develop an application without having to repeatedly update initialValue when I redeploy the application?

    For example, (1) I deploy the application, and I persist some entities using the web application, (2) I undeploy the application and modify its source code, and (3) I redeploy the application to test my changes. If I don’t update initialValue between steps 1 and 3, will I overwrite entities or otherwise get errors?

    (I will test this myself when I have time, but if you have time I would appreciate your explanation of this.)

    • Hello David, how are you?

      That is a very good question and I do not know the answer without a test too. =/

      Thanks for passing by

Leave a Comment