[RESOLVIDO] Hibernate + Java DB embarcado: cria mas não mantém dados na base

10 respostas
V

Pessoal,

Estou desenvolvendo uma aplicação swing standalone com java web start, usando hibernate para acessar o java db embarcado nesta aplicação.
Em teste com a IDE os dados são mantidos neste banco.

Porém, ao executar fora da IDE os dados só são mantidos enquanto a aplicação está ativa. Se fechá-la e abrí-la novamente os dados já não estão mais lá.

Como proceder para que possa distribuir tal aplicação e o banco de dados ser criado na primeira execução e nos demais acessos ocorrer apenas atualizações nas tabelas deste banco, quando necessário ?

hibernante.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.apache.derby.jdbc.EmbeddedDriver</property>
        <property name="hibernate.connection.url">jdbc:derby:minhabase;create=true</property>
        <property name="hibernate.connection.username">usuario</property>
        <property name="hibernate.connection.password">senha</property>
        <property name="hibernate.show_sql">false</property>
        <property name="hibernate.format_sql">false</property>
        <property name="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</property>
        <property name="hibernate.hbm2ddl.auto">create</property>
        <property name="hibernate.connection.pool_size">1</property>
        <property name="hibernate.dialect">org.hibernate.dialect.DerbyDialect</property>
        <property name="hibernate.default_schema">app</property>
        <property name="hibernate.current_session_context_class">thread</property>    
        <mapping class="com.tfv.model.Cliente"/>
        <mapping class="com.tfv.model.CondicaoPagamento"/>
        <mapping class="com.tfv.model.Produto"/>
    </session-factory>
</hibernate-configuration>
HibernateUtil.java:
public class HibernateUtil {

    private static final SessionFactory sessionFactory;
    
    static {
        try {
            // Create the SessionFactory from standard (hibernate.cfg.xml) 
            // config file.
            sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Log the exception. 
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

GenericDAO.java:

public class GenericDAO<T extends Serializable> {

    private Session sessao;
    private final Class<T> classePersistente;

    public GenericDAO() {
        this.sessao = HibernateUtil.getSessionFactory().getCurrentSession();
        this.classePersistente = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public Session getSessao() {
        return sessao;
    }

    protected void salvar(T entity) {
        try {
            this.sessao.beginTransaction().begin();
            this.sessao.save(entity);
            this.sessao.beginTransaction().commit();
        } catch (Throwable t) {
            this.sessao.getTransaction().rollback();
            t.printStackTrace();
        } finally {
            fecharSessao();
        }
    }

    protected void alterar(T entity) {
        try {
            this.sessao.beginTransaction().begin();
            this.sessao.update(entity);
            this.sessao.beginTransaction().commit();
        } catch (Throwable t) {
            this.sessao.getTransaction().rollback();
            t.printStackTrace();
        } finally {
            fecharSessao();
        }
    }

    protected void deletar(T entity) {
        try {
            this.sessao.beginTransaction().begin();
            this.sessao.delete(entity);
            this.sessao.beginTransaction().commit();
        } catch (Throwable t) {
            this.sessao.getTransaction().rollback();
            t.printStackTrace();
        } finally {
            fecharSessao();
        }
    }

    /**
     * retorna todos os registros de determinada tabela.
     *
     * @return
     * @throws Exception
     */
    public List<T> BuscaTodos() throws Exception {
        return this.sessao.createCriteria(classePersistente).list();
    }

    /**
     * método para retornar registros que possuem determinada string no campo
     * indicado no primeiro parâmetro.
     *
     * @param campo - nome do campo por onde será pesquisado.
     * @param conteudo - conteúdo a ser pesquisado no campo informado no 1º
     * parâmetro.
     * @return
     */
    public List<T> BuscaCampoString(String campo, String conteudo) {
        this.sessao.beginTransaction().begin();
        List<T> aResultado = this.sessao.createCriteria(classePersistente).add(Restrictions.like(campo.toString(), "%" + conteudo + "%").ignoreCase()).list();
        this.sessao.beginTransaction().commit();
        fecharSessao();
        return aResultado;
    }

    /**
     * método para retornar registro que possui determinada id passada como
     * parâmetro.
     *
     * @param campo - nome do campo chave-primária
     * @param id - conteúdo a ser pesquisado no campo chave-primária
     * @return
     */
    public T BuscaCampoId(String campo, String id) {
        this.sessao.beginTransaction().begin();
        T oResultado = (T) this.sessao.createCriteria(classePersistente).add(Restrictions.eq(campo.toString(), id)).uniqueResult();
        this.sessao.beginTransaction().commit();
        fecharSessao();
        return oResultado;
    }

    public void fecharSessao() {
        if (this.sessao != null && this.sessao.isOpen()) {
            this.sessao.getTransaction().commit();
            this.sessao.close();
        }
    }
}

ClienteDAO.java:

public class ClienteDAO extends GenericDAO<Cliente> {
    
    @Override
    public void salvar(Cliente cliente){
        salvar(cliente);        
    }
    
    @Override
    public void alterar(Cliente cliente){
        alterar(cliente);
    }
    
    public void deletar(String id){
        Cliente c = BuscaCampoId("id", id);
        deletar(c);
    }
}
Exemplo de gravação de um cliente:
...
            sessao = HibernateUtil.getSessionFactory().openSession();
            sessao.beginTransaction().begin();

                Cliente cliente = new Cliente();
... cliente.sets ...
                sessao.saveOrUpdate(cliente);
            sessao.getTransaction().commit();
            sessao.close();

10 Respostas

R

Se não me falha a memória, se você usa o “create=true” na string de conexão, toda vez que iniciar a aplicação ele vai recriar o banco, sendo assim, exclui os dados antigos.

V

Pois é. Isto resolveria eu liberando uma primeira versão com create=true e depois que todos instalassem a aplicação e executassem, liberaria nova versão sem o create=true. Mas, não tem nada melhor que isto ? Como fazer para distribuir esta aplicação java web start, ela criando no primeiro uso o banco e nos demais não criando, sem ser desta forma citada ? Suponho que deva fazer isto no HibernateUtil.java . Estou certo ?

Nos demais, apenas atualizar as tabelas quando se fizer necessário. Para isto sei que o <property name="hibernate.hbm2ddl.auto"> com create cria e com update atualiza as estruturas das tabelas.

No aguardo do auxílio :slight_smile:

R

Não sei como resolver em relação ao DerbyDB, mas você poderia utilizar o HSQLDB, dai não vai ter esse problema, porque ele não usa esse parâmetro na url.

V

Obrigado romarcio pela colaboração, mas pretendo usar o java db.

Alguém mais pode ajudar ?

R

Acho que você poderia passar sua configuração para uma configuração programática e não por xml. Dai, talvez, você consiga ao iniciar a aplicação fazer um rotina que testa se o banco já existe, se existir, você passa propriedade normal da url, sem o parâmetro “creat-true”, caso contrário, passa com o parâmetro.

V

romarcio,

Segui teu conselho e mudei para HSQLDB. Só estou emperrando no seguinte: ao tentar abrir a sessão ocorre o erro:

2013-05-02T12:27:38.026-0300 SEVERE could not reopen database
org.hsqldb.HsqlException: Database lock acquisition failure: lockFile: org.hsqldb.persist.LockFile@c54735ed[file =C:\Users\vicente\Documents\NetBeansProjects\TFV\banco\banco".lck, exists=false, locked=false, valid=false, ] method: openRAF reason: java.io.FileNotFoundException: C:\Users\vicente\Documents\NetBeansProjects\TFV\banco\banco".lck (A sintaxe do nome do arquivo, do nome do diretório ou do rótulo do volume está incorreta)

Este erro aconteceu após tentar abrir a sessão:

HibernateUtil não mechi. continua como informado anteriormente.

Olha meu hibernate.cfg.xml como ficou:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="hibernate.connection.url">jdbc:hsqldb:file:banco/banco"</property> <property name="hibernate.connection.username">usuario</property> <property name="hibernate.connection.password">senha</property> <property name="hibernate.show_sql">false</property> <property name="hibernate.format_sql">false</property> <property name="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</property> <property name="hibernate.hbm2ddl.auto">update</property> <property name="hibernate.connection.pool_size">1</property> <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property> <property name="hibernate.default_schema">app</property> <property name="hibernate.current_session_context_class">thread</property> <mapping class="com.tfv.model.Cliente"/> <mapping class="com.tfv.model.CondicaoPagamento"/> <mapping class="com.tfv.model.Produto"/> </session-factory> </hibernate-configuration>

R

Tenta assim:<property name="hibernate.connection.url">jdbc:hsqldb:file:./banco/banco"</property>

V

romarcio,

infelizmente continua o mesmo erro.

R

vicentedepaula:
romarcio,

infelizmente continua o mesmo erro.

:cry: Não sei o que pode ser.

Mas tem uma coisa estranha no erro, java.io.FileNotFoundException: C:\Users\vicente\Documents\NetBeansProjects\TFV\banco\banco".lck o HSQLDB não cria arquivo .lck, isso é coisa do Derby.

V

romarcio,

obrigado pela ajuda. Descobri o problema. Primeiro mudei para

Em seguida percebi que na consulta que eu estava fazendo, havia um campo que era alimentado apenas quando a aplicação java web start funcionava no modo on-line. E tal campo servia como filtro para as demais tabelas. Descoberto isto, só foi tratar a persistência deste campo na sua entidade e o problema foi solucionado.

Continuo usando o JavaDB. Com relação ao create=true usado no hibernate.connection.url, visualizei no console o seguinte:

[color=red]WARNING: Database ‘minhabase’ not created, connection made to existing database instead.[/color]

Manterei create=true até quando não houver nenhum usuário novo da aplicação.

Criado 1 de maio de 2013
Ultima resposta 9 de mai. de 2013
Respostas 10
Participantes 2