[RESOLVIDO] Auto incremente no Firebird com Hibernate

5 respostas
root_

Olhei um pouco na net sobre isso, inclusive claro aqui no forum, mais n satisfeito com “quebra galho”, estou postando minha soluçao!
Consideraçoes:

  • Estou usando Firebird em modo SuperServer versao 2.0.3 (winXP).
  • JDK 6.0 update 3.
  • Hibernate Annotations.

CLASSE HIBERNATE_ UTIL:

public class HibernateUtil extends java.lang.Object
{
    private static SessionFactory sessionFactory;
    //Pegando as informaçoes das propriedades de conexao com a base de dados do software...
    private static String usuario = SdpConexao.sdpProps.getProperties().getProperty("db.usuario");
    private static String senha = SdpConexao.sdpProps.getProperties().getProperty("db.senha");
    private static String dbUrl = SdpConexao.sdpProps.getProperties().getProperty("db.url");
    
    
    //Criando uma threadLocal garantindo que seja reutilizada a sessao aberta, caso ja exista;
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    static
    {
        
        try
        {
              System.out.println("USER db: " + usuario + " \n senha: " + senha 
                      + "\n URL: " + dbUrl);
              
             sessionFactory = new AnnotationConfiguration().configure("sdp2000/hibernate.cfg.xml")
                     .setProperty("hibernate.connection.username", usuario)
                     .setProperty("hibernate.connection.password", senha)
                     .setProperty("hibernate.connection.url", dbUrl)
                     .buildSessionFactory();
           
        } 
        catch (Exception e)
        {
            sessionFactory = null;
            e.printStackTrace();
            System.exit(0);
        }
    }

    public static Session getSession()
    {
        Session localSession = threadLocal.get();
        localSession = sessionFactory.openSession();
        threadLocal.set(localSession);
        return localSession;
    }
    
    public static void initConfMaps()
    {
        try
        {
            Session localSession = threadLocal.get();
            localSession = sessionFactory.openSession();
            threadLocal.set(localSession);
            localSession.close();
            
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }  	
 
}

=============================================================================
Sabemos que no Firebird para criar um campo AUTOINCREMENT é preciso criar um GENERATOR para o ID (que é pra ser automatico o incremento)
e uma trigger para executá-lo toda vez que algo for inserido no DB.
No caso de usar o Hibernate, não é preciso criar a trigger, pq ele vai fazer essa computação de incrementar o GENERATOR.

Agora a parte do código em questao (a do auto increment) na minha classe mapeada:

@Entity
@Table(name="CLIENTE")
public class Cliente implements Serializable 
{
    private static final long serialVersionUID = 1L;
    
    @Id @SequenceGenerator(name = "GEN_ID_CLIENTE", sequenceName = "GEN_CLIENTE_ID")  
    @GeneratedValue(strategy = GenerationType.AUTO, generator="GEN_ID_CLIENTE")
    private Integer id_cliente;
.
.
.
metodos Gets e Sets e bla bla bla.....
}

E agora, por fim a classe ClienteDAO, que é minha interface de controle entre Obj Cliente e tabela Cliente do DB.
Ainda em construçao a classe, mais o que interessa ja está pronto. Que é o rollback do generator caso aconteça um erro ao Salvar um novo registro no DB. Foi necessario a criaçao desse rollBackID porque, quando na tentativa de salvar um novo obj no DB, a primeira coisa a ser calculado é o campo de “auto increment”, a segunda é realiar a persistencia. Se ocorrer erro na persistencia, ele n volta o GENERATPOR (rollBack do calculo do Generator para o proximo valor). Isso causa furos no sequenciamento do ID.

Caso aconteça algum Excepiton no método salve() no seu código, utilize o método rollBak() que está na classe abaixo .

/*
 * ClietenDAO.java
 *
 * Criada em 06 de Desembro de 2007, 14:49
 *
 *  Interface de Controle de Acesso a DADOS do tipo Cliente
 *
 */
package sdp2000.persistencia;
import java.util.List;
import org.hibernate.*;
import modCadastro.Cliente;
import org.hibernate.criterion.Example;
/**
 *
 * @author Rogerio M.Q
 */
public class ClienteDAO
{
    private static Session sessao;
    /** Creates a new instance of GenericDAO */

    public void save( Cliente cliente ) throws Exception
    {
            sessao = HibernateUtil.getSession();
            sessao.beginTransaction();
            sessao.save(cliente);
            sessao.flush();
            sessao.getTransaction().commit();
            sessao.close();
    }

    public void update( Cliente cliente ) throws Exception
    {
            sessao = HibernateUtil.getSession();
            sessao.beginTransaction();

            sessao.update(cliente);
            sessao.flush();
            sessao.getTransaction().commit();
            sessao.close();

    }
    public void salveOrUpdate( Cliente cliente ) throws Exception
    {
            sessao = HibernateUtil.getSession();
            sessao.beginTransaction();
            sessao.saveOrUpdate(cliente);
            sessao.flush();
            sessao.clear();
            sessao.getTransaction().commit();
            sessao.close();
    }

    public void delete( Cliente cliente ) throws Exception
    {
            sessao = HibernateUtil.getSession();
            sessao.beginTransaction();
            sessao.delete(cliente);
            sessao.flush();
           sessao.getTransaction().commit();
            sessao.close();

    }

    public List listar(Class clazz) throws Exception
    {
        sessao = HibernateUtil.getSession();
        sessao.beginTransaction();
        Cliente exemplo = new Cliente();
        exemplo.setStatus_cliente('T');
        
        List clientes;
        clientes = null;
        Criteria selectAll_T = sessao.createCriteria(clazz).add(Example.create(exemplo)); //revisar 
        sessao.getTransaction().commit();
        clientes = selectAll_T.list();
        sessao.close();
        return clientes;
    }
    

    // Recupera um Registro do Banco, salva em um clienteeto e o retorna para funcao q o chamou.
    public Cliente listar(String pk) throws Exception
    {
        sessao = HibernateUtil.getSession();
        sessao.beginTransaction();
        Cliente cliente = null;
        cliente = (Cliente) sessao.get(Cliente.class, new Integer(Integer.parseInt(pk)) );
          
        sessao.getTransaction().commit();
        sessao.flush();
        sessao.close();
        return cliente;
    }
    
   /* Apesar de voltar a ação mal sucedida da SLQ criada pelo hibernate,
       no caso uma inserção, o GENERATOR_ID ja foi calculado no FirebirdSQL e assim fujindo da ordem,
       entao restartamos o GENERATOR_ID o ultimo maior Id inserido...
    * 
    * 
    *  rollBack customizado para tabela Cliente.
    */
    public void rollBack() throws Exception
    {
        if(sessao.getTransaction()!=null)
        {       
                  sessao.getTransaction().rollback();
                  String rollbackID = "SET GENERATOR GEN_CLIENTE_ID TO " + (getMaxID());
                  sessao.createSQLQuery(rollbackID).executeUpdate();
        }
        sessao.close();
    }
    private int getMaxID()
    {
        Object obj = sessao.createSQLQuery("SELECT MAX(ID_CLIENTE) AS ID_CLIENTE FROM CLIENTE").uniqueResult();

        return Integer.parseInt( obj.toString() );
    }

}

qualquer dúvida, estamos ai!

5 Respostas

targas

NO meu caso, tenho um sistema multi empresas, desta forma a chave é gerada num trigger sem generator conforme abaixo:

CREATE OR ALTER TRIGGER TBA_MOEDAS_BI0 FOR TBA_MOEDAS

ACTIVE BEFORE INSERT POSITION 0

AS

DECLARE WID INTEGER;

BEGIN

SELECT MAX(ID) FROM TBA_MOEDAS

WHERE CLIENTE_SISTEMA_ID = NEW.CLIENTE_SISTEMA_ID

INTO WID;

IF (WID IS NULL) THEN
BEGIN
WID = 0;
END

NEW.ID = WID + 1;
END

Como devo fazer as anotações neste caso?

root_

Neste caso acho que não precisará de definir as anotações referentes ao generator…
já deve resolver…

ViniGodoy

Por favor, ao postar tópicos, não deixe os títulos apenas com letras maiúsculas.

Para conhecer outras regras de netiquetas envolvendo fóruns, leia:
http://www.istf.com.br/perguntas/

root_

ViniGodoy:
Por favor, ao postar tópicos, não deixe os títulos apenas com letras maiúsculas.

Para conhecer outras regras de netiquetas envolvendo fóruns, leia:
http://www.istf.com.br/perguntas/

Não fui eu quem colocou o título como UPPERCASE… alias, agora que reparei isso… porém o título do tópico está normal.
Já aparece assim quando clicamos em responder!!!

ViniGodoy

O título do tópico está normal agora porque eu corrigi. Mas ele foi aberto em uppercase, por isso o aviso.

Criado 7 de dezembro de 2007
Ultima resposta 14 de fev. de 2012
Respostas 5
Participantes 3