JPA SequenceGenerator

THERE IS A NEW VERSION OF THIS POST.
CLICK HERE: http://uaihebert.com/?p=1674&page=6

Hello, how are you?

Let us talk today about a Primary Key generator named “SequenceGenerator”. In the last post (JPA TableGenerator – Simple Primay Key) we talked about the TableGenerator and how to solve the fact of having only one Sequence to all tables in our system.

What if we see today how to create a sequence per Table (Class)? If the TableGenerator is giving your code the feeling of “a dirty code”, we can eliminate this “feeling” removing the TableGenerator and using the SequenceGenerator instead.

With a sequence per table we have the same Key Generation that we have using the TableGenerator, but with less configuration code inside our classes.

I remember that we will be using in this post the Hibernate implementation and the JPA implementation provided by Hibernate. If you wish, you can use any JPA implementation that provides automatic schema generation.

I will start exactly where we stopped in the last post (JPA TableGenerator – Simple Primay Key). We will do some updates in the class User and Dog replacing the TableGenerator for SequenceGenerator.

I will write bellow how our classes were and how it will be. If you want to set up the environment to run the code, in this post (JPA TableGenerator – Simple Primay Key) you can see the tutorial step by step.

How our classesconfigurations are today:

<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">

    <persistence-unit name="Hello" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>

        <properties>
            <property name="hibernate.show_sql" value="true" />
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/postgres"/>
            <property name="javax.persistence.jdbc.user" value="postgres" />
            <property name="javax.persistence.jdbc.password" value="postgres" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.default_schema" value="hello"/>
        </properties>
    </persistence-unit>
</persistence>
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="USER")
public class User{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @TableGenerator(name="USER_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="USER_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="USER_GENERATOR")
    private int id;

    @Column
    private String name;

    @Column
    private String password;

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof User){
            User user = (User) obj;
            return user.getId() == this.getId();
        }

        return false;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package com;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

@Entity
@Table(name="DOG")
public class Dog {

    @TableGenerator(name="DOG_GENERATOR",
            table="GENERATED_KEYS",
            pkColumnName="PK_COLUMN",
            valueColumnName="VALUE_COLUMN",
            pkColumnValue="DOG_ID",
            allocationSize=1
    )
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator="DOG_GENERATOR")
    private int id;
    @Column
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("Hello");
        EntityManager em = emf.createEntityManager();

        try {
            em.getTransaction().begin();

            User user = new User();
            user.setName("abc123");
            user.setPassword("abc123");
            em.persist(user);

            Dog dog = new Dog();
            dog.setName("pineapple");
            em.persist(dog);

            em.getTransaction().commit();
        }
        catch (Exception e) {
            em.getTransaction().rollback();
            e.printStackTrace();
        }
        finally{
            emf.close();
        }

        System.out.println("It is over");
    }
}

The lines with the @TableGenerator annotation indicate the TableGeneration Strategy code that we use. There are a lot of lines to do a simple function.

To update your code to SequenceGenerator you just have to edit the code has the some lines of the bellow code:

package com;

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

@Entity
@Table(name="USER")
@SequenceGenerator(name="USER_SEQUENCE", sequenceName="USER_SEQUENCE", allocationSize=1, initialValue=0)
public class User{
    /**
     *
     */
    private static final long serialVersionUID = 1L;

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

    @Column
    private String name;

    @Column
    private String password;

    @Override
    public boolean equals(Object obj) {
        if(obj instanceof User){
            User user = (User) obj;
            return user.getId() == this.getId();
        }

        return false;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package com;

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

@Entity
@Table(name="DOG")
@SequenceGenerator(name="DOG_SEQUENCE", sequenceName="DOG_SEQUENCE", allocationSize=1, initialValue=0)
public class Dog {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="DOG_SEQUENCE")
    private int id;
    @Column
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

The code above with the @SequenceGenerator indicate the lines that you will have to change to replace the TableGenerator for SequenceGenerator.

Let us see more details about the SequenceGenerator parameters:

  • name = the sequence name. The ID will use this name as a key to locate the created sequence.
  • sequenceName = name of the sequence that will be created (or used) in the database.
  • allocationSize = The value that will be incremented for each new database record. The default value is 1 but, if we set to 2 the first record will have the ID 2, the next 4…
  • initialValue = The sequence start value.

Let us run the Main class and see the results:

Console Image.

Notice that the Hibernate did a query searching for the next id value. The Hibernate created the sequence when we start up the application, this creation process occurs just when the sequence is not located.

Sequence Image.

I hope this post might help you.

If you have any question/suggestion just post it.

See you later.

Leave a Comment