JPA TableGenerator – Chave Primária Simples

EXISTE UMA NOVA VERSÃO DESSE POST.
CLICK AQUI: http://uaihebert.com/?p=1622&page=7

Bom dia, tudo bem você?

Vamos ver hoje como utilizar o recurso chamado TableGenerator. No primeiro post sobre o assunto (Tutorial Hibernate 3 com JPA 2), o Hibernate criou de modo automático para gerar o id da classe, uma sequence. Essa sequence (“hibernate_sequence”) é responsável por armazenar o ID da classe User, e sempre fornecer o próximo número do ID de um novo objeto a ser inserido no DB.

Com isso, se você criar um usuário o ID seria 1 (um). O próximo usuário criado teria seu ID igual a 2. Caso você criasse uma classe Cachorro e mandasse incluir no banco de dados, o ID do cachorro seria 3 mesmo sendo o primeiro cachorro criado.

O TableGenerator vem como uma solução alternativa caso essa abordagem de sequence te gere algum problema.

Se você quiser ver uma abordagem detalhada de como criar/configurar uma aplicação desde a instalação de banco de dados e configurações você pode ver nesse tópico aqui: Tutorial Hibernate 3 com JPA 2.

A única diferença do post de hoje para o primeiro post com um Hello World (Tutorial Hibernate 3 com JPA 2), é que estarei utilizando o Postgres como banco de dados e não o MySQL. O processo de instalação e configuração é o mesmo.

Não se esqueça de criar o schema no banco de dados que você estiver utilizando. Em nosso caso estaremos utilizando um schema chamado Hello.

Vamos começar com os downloads, Hibernate/JPA3. Estaremos utilizando a implementação do Hibernate que é encontrada no arquivo que você irá fazer o download.

No meu caso, estou utilizando o banco de dados do Postgres, será necessário fazer o download do Driver (JDBC4 Postgresql DriverCaso você queria procurar Drivers mais novos.). Você poderá utilizar qualquer outro banco de dados. No primeiro post mostra a configuração do MySQL (Tutorial Hibernate 3 com JPA 2).

Após criar um projeto do tipo “Java Project”, crie uma pasta com o nome “lib” dentro da pasta “src”. Dentro dela deve ficar todos os arquivos do tipo jar (tanto o Drive como as bibliotecas do Hibernate). Deve ficar como nessa foto. No post Tutorial Hibernate 3 com JPA 2 ensina esse processo de modo detalhado.

Precisamos adicionar os arquivos ao Build Path da aplicação. Botão direito sobre o nome do projeto > Properties > Java Build Path > Add Jars. Selecione os arquivos que você colocou dentro da pasta lib. No post Tutorial Hibernate 3 com JPA 2 ensina esse processo de modo detalhado.

Crie uma pasta chamada “META-INF” dentro da pasta “src”. Dentro da pasta “META-INF” crie um arquivo chamado “persistence.xml” e cole o código abaixo. (Passo a passo aqui Tutorial Hibernate 3 com JPA 2).

<?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>

As linhas em destaque são as linhas que precisariam sofrer alteração caso você utilize um banco de dados diferente.

Vamos criar agora as classes que serão persistidas. Vamos utilizar uma classe User e uma classe Dog.

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;
    }
}

Vou explicar os campos da anotação TableGenerator:

  • name = Nome dado ao TableGenerator criado. Ele será utilizado pelo ID ao buscar por uma identificação.
  • table = tabela que será utilizada para armazenar as chaves primárias criadas. Em nosso caso, o “persistence.xml” está marcado para criar as tabelas que ainda não existem de modo automático (“<property name=”hibernate.hbm2ddl.auto” value=”update”/>”). Por esse motivo não é necessário criarmos essa tabela, pois após a execução da classe Main, essa tabela já existirá em nosso banco de dados.
  • pkColumnName = nome da coluna em que irá gravar um texto contendo o nome do ID. Em nosso caso, esse nome é definido através do pkColumnValue que é USER_ID. (Você verá ao final, em uma imagem, como esse valor é armazenado na tabela).
  • valueColumnName = nome da coluna que irá registrar o valor do contador que irá sempre incrementar nosso ID.
  • pkColumnValue = Valor que servirá de par para o valueColumnName. Por exemplo: “USER_ID | 1″ e depois “USER_ID | 2″
  • allocationSize = O valor que será acrescido a cada novo registro. Estamos adicionando sempre um, caso fosse 2 o primeiro usuário criado teria seu ID 2 o segundo 4 e assim vai.

E por último precisamos de uma classe que execute nosso código, realizando a persistência no banco de dados.

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");
    }
}

Após executar a classe Main, basta consultar no banco de dados os 3 resultados que devem aparecer de acordo com o que foi exibido no console.

Console

Consulta tabela User

Consulta tabela Dog

Consulta a tabela de PKs

O valor na tabela de chaves primárias está como 2 não é por que deu algum erro, mas por que ele salva o valor da próxima chave a ser gerada. Quando for inserir um novo registro, o Hibernate irá consultar qual o próximo valor, utilizará, e salvará o valor acrescido de um.

Apesar de utilizar o Hibernate no exemplo de hoje, qualquer outro provedor de persistência (Hibernate, EclipseLink, etc) que forneça geração automática de schema, poderá ser utilizado para esse exemplo.

Ficou alguma dúvida? Sugestão? Basta comentar que irei responder.

Até a próxima.