Objetos de Entidade de BD do JPA não atualiza, o que fazer?

Olá pessoal!

estou desenvolvendo um sistema com swing e JPA.
tenho minhas classes geradas a partir das tabelas do BD e o programa funciona assim:

  • Clico em um botão da janela e um conteúdo do Banco de dados é mostrado no centro dela em uma JTable .

  • O problema ocorre quando eu modifico um dado no BD (um nome de um funcionário, por exemplo) e mesmo quando limpo todos os componentes da janela e clico para exibir os dados novamente, eles continuam os mesmos. Parece que os objetos JPA não são atualizados.

  • E no meu código sempre que o botão é cllicado é criada uma nova instancia, mas não está atualizando os dados do BD.

Qual o problema e a Solução???

Usar JPA/Hibernate é uma grande aventura. Depende de como está implementado. Certifique se está abrindo uma nova session a cada ação do usuário, senão ele vai pegar do cache mesmo.

OLÁ,
sou novo nessa aventura e o que vc quer dizer com “abrindo uma nova session”?
vc se refere a fechar e abrir um novo EntityManagerFactory a cada acao?

Na época que usava Java tinha o SessionFactory (instancia que deve ser única, alocado na aplicação a vida toda). Com ele chamava o método openSession para abrir a conexão com o banco. Seja lá qual for o “comando” ou mágica hoje, cada vez que o usuário realizar uma ação no sistema, a conexão com o banco de dados deverá ser aberta e fechada assim que terminar de retornar os dados pro usuário. Dependendo de como estiver implementado, se manter a session (não SessionFactory) aberta a vida toda corre o risco dele ler do cache ao invés do banco de dados.

Aí, consegui usando esses métodos usados sobre o EntityManagerFactory a cada listagem e antes de fechá-lo;

Model.FACTORY.getCache().evictAll();
fJpaC.getEntityManager().clear();

Model.FACTORY.close();

Isso funciona, mas evict é pra ser usado em último caso em situações anormais. Provavelmente está usando cache sem necessidade, deixando a conexão sempre aberta, ou algo que vá ficar encoberto e sendo remediado por evicts.

Curioso que cache quando realmente necessário é um dos poucos motivos para se usar JPA/Hibernate, a não ser que esteja usando vários SGDBs ao mesmo tempo.

Bom não sei se entendi muito bem seu problema, mas segue um exemplo de como eu realizo as atualizações… na minha classe dao.

`
Session sessao = HibernateUtil.getSessionFactory().openSession();
Transaction transacao = null;

	try {
		transacao = sessao.beginTransaction();
		sessao.update(funcionario);

		transacao.commit();
	} catch (RuntimeException ex) {
		if (transacao != null) {
			transacao.rollback();
		}
		throw ex;
	} finally {
		sessao.close();
	}`

lembrando que após realizar um update ou alguma outra coisa, tem que realizar o update do table via ajax. :smiley:

Exatamente, essa é a forma normal de se trabalhar, em que não seria necessário ficar usando evict.

A atualização que eu me refiro, Deivid, é uma consulta (um select usando JPA). O problema é que essa consulta mostra sempre os mesmos dados, ainda que eu modifique os dados no BD usando o phpmyadmin, por exemplo. Aí quando clico pra listar os dados novamente ele não muda.
vou verificar e aplicar o código que vcs me passaram e informo o resultado sem usar evict.

ah e o meu app é desktop, não uso ajax.

Se você fizer como o exemplo que ele passou, sendo que para consulta, continua o problema?

Session sessao = sessionFactory.openSession();

Query query = sessao.createQuery("from Cliente where id = :id ");

query.setParameter("id", "123");

List resultado = query.list();

//....passa o resultado pra um DTO, ModelView ou que for que esteja usando pra servir de interface pra atender a UI.......

sessao.close();

E não são mesmo. A ferramenta não é feita pra funcionar dessa maneira, onde você altera o banco por fora do JPA.

Olá gente, agradeço muito a ajuda de vcs. Encontrei o meu erro!
Como eu estou entrando agora nessa onda de JPA desconhecia que sempre temos que criar uma nova EntityManagerFactory a cada interação com o BD e sempre fechá-la. Eu usava um EntityManagerFactory único em uma variável static por achar que cada abertura deixaria o programa pesado, mas não.
Eis aki o meu código SEM ERROS.

public class PainelListaDeFuncionarios extends javax.swing.JPanel implements ActionListener{
private final DefaultTableModel modelo1;
private final JanelaPrincipal janelaPai;

List<Funcionario> funcionarios = null;
EntityManagerFactory fctr;

public PainelListaDeFuncionarios(JFrame janelaPai) {
this.janelaPai = (JanelaPrincipal) janelaPai;
initComponents();
modelo1 = (DefaultTableModel) tabelaFuncs.getModel();

    fctr = Persistence.createEntityManagerFactory("com.sigef_jar_1.0-SNAPSHOTPU");
    FuncionarioJpaController fJpaC =
            new FuncionarioJpaController(fctr);
    
    funcionarios = fJpaC.findFuncionarioEntities();
    
    int numRow = modelo1.getRowCount();
    Object[] line; 
    Funcionario funcion;
    
    for (int idx = 0; idx < funcionarios.size(); idx++) {
        funcion = funcionarios.get(idx);  
        
        line = new Object[]{
            funcion.getPessoa().getPessoaPK().getId(),
            funcion.getPessoa().getNome(),
            funcion.getCargo().getNome(),
            funcion.getPessoa().getNascimentoData()
        };
        modelo1.addRow(line);            
    }
    
  
    
    //IMPORTANTE PARA FECHAR AS CONEXÕES DO BD
    fctr.close();

}

}

temos que sempre abrir com o createEntityManagerFactory() e fechar. Erro grosseiro! Mas valeu a experiência. Obrigado gente!
agora meu software vai ficar perfeito.

Pois é, mas já que insistem em usar JPA/Hibernate sem sem ter a necessidade dessa coisa toda de cache, então ele vai ter que reabrir a conexão a cada consulta ou usar StatelessSession. Ele está usando uma ferramenta que está atrapalhando mais do que ajudando, ou se ao menos tivesse justificado o uso, como por exemplo multibanco.

Parabéns por considerar a solução ideal (considerando se realmente vai querer usar Hibernate).

Curioso como muitas coisas em java só aprendemos dessa forma, errando e consultando fóruns!!
:smile::smile:

Errado. O JavaDoc do EntityManagerFactory diz:

When the application has finished using the entity manager factory, and/or at application shutdown, the application should close the entity manager factory. Once an EntityManagerFactory has been closed, all its entity managers are considered to be in the closed state.

Eita verdade, verdade!

não fechei o EntityManagerFactory e funcionou da mesma forma! Agora tenho que criar apenas um EntityManagerFactory e usá-lo sempre em todas as classes e fechar apenas quando a aplicação for fechada?

Mas não existe essa opção de usar JPA mas não “toda essa coisa de cache”. rs

Achei que tivesse fechado só a session como o exemplo que passamos. O factory não é para fechar não! Factory é super pesado deve existir uma única instância em todo a vida da aplicação como já explicado no início.

Não entendi o que você quis dizer.