Solucionado (ver solução)
Solucionado
(ver solução)
19
respostas

Lista muda os valores com refresh

Por exemplo, eu tenho uma lista de produtos. Em cada um deles eu coloquei a opção de editar. Ao escolher um produto e alterar o campo tudo funciona normalmente, o produto aparece alterado corretamente. Mas ao dar um refresh, o produto volta como estava antes, e se der outro refresh ele aparece alterado, e fica nesse loop, em cada refresh a tabela alterna com os dados do produto.

19 respostas

Opa, aí temos um problema realmente bem estranho. Cada refresh refaz a última operação, teria que ver algo no seu código para tentarmos achar...

Meu código está certo, parece ser um problema de cache ... Talvez faltem algumas configurações no persistence.xml com relação a cache, o que você acha?

Complicado... Não consegui ver relação entre o cache e essa troca de informações. Acho que você precisa colocar um debug no método do controller que gera essa atualização, para tentar descobrir o que acontece de fato.

Aqui print do que está ocorrendo:

Tabela normal: https://drive.google.com/open?id=0B7NlcsEHVJhhV3g0LTJGbzd0cms

Após editar: https://drive.google.com/open?id=0B7NlcsEHVJhhLUdNYlZBRk5zUFk

O valor do campo nome fica alternando nesses valores a cada refresh.

Ao dar um Clean no projeto, o problema é resolvido temporariamente. Chega um momento que o mesmo problema retorna.

Como faço pra descobrir com o debug?

Alguém?

Oi Thiago,

você tentou debugar o método no controller que faz o update? Se sim, encontrou alguma coisa estranha na hora de carregar a página de novo? Teria como você mostrar os trechos do código que fazem esse processo todo? Assim fica mais fácil para entendermos o problema.

Aqui está meu código :

UsuarioController:

@Controller
public class UsuarioController {

    private UsuarioDao usuarioDao;
    private Result result;
    private Validator validator;

    @Inject
    public UsuarioController(UsuarioDao usuarioDao    , Result result, Validator validator) {
        this.usuarioDao = usuarioDao;
        this.result = result;
        this.validator = validator;
    }

    public UsuarioController(){}

    @Path("usuarios/lista")
    public void lista() {
        List<Usuario> usuarios = usuarioDao.lista();
        result.include("tipoUsuario", TipoUsuario.values());
        result.include("usuarios",usuarios);
    }

    @Path("/usuarios/novo")
    public void novo() {
        result.include("tipoUsuario", TipoUsuario.values());
    }

    @IncludeParameters
    public void adiciona(@Valid Usuario usuario) {
        validator.onErrorRedirectTo(this).novo();
        usuarioDao.adiciona(usuario);
        result.redirectTo(this).lista();
    }

UsuarioDao:

@RequestScoped
public class UsuarioDao {

    private EntityManager manager;

    @Inject
    public UsuarioDao (EntityManager manager){
        this.manager = manager; 
    }

    public UsuarioDao(){}

    public void adiciona(Usuario usuario) {
        try {
            manager.getTransaction().begin();
            manager.persist(usuario);
            manager.getTransaction().commit();
        }catch (Exception e) {
            manager.getTransaction().rollback();
        }
    }

    public List<Usuario> lista() {
        try{
            TypedQuery<Usuario> query = manager.createQuery("select u from Usuario u", Usuario.class);
            return query.getResultList();
        }finally{
            manager.close();
        }
    }

Form de cadastro:

<form class="form-style" action="${linkTo[UsuarioController].adiciona(null)}" method="post">
    <label for="nome">Nome do usuário:</label>
    <input type="text" name="usuario.nome" id="nome" class="form-control" placeholder="Nome Completo" value="${usuario.nome}" required/>

    <label for="email">Email:</label>
    <input type="text" name="usuario.email" id="email" class="form-control" placeholder="Seu endereço de email" value="${usuario.email}" required/>
...
    <input type="submit" class="btn btn-red" value="Cadastrar Usuário" />
</form>

Lista:

<table class="table" id="tabela">
    <thead>
        ...
    </thead>
    <tbody class="usuario-body">
        <c:forEach items="${usuarios}" var="usuario">
            <tr class="usuario">
                <td id="id">${usuario.id}</td>
                <td id="nome">${usuario.nome}</td>
                <td id="email">${usuario.email}</td>
                <td id="login">${usuario.login}</td>
                <td id="tipo">${usuario.tipo}</td>
                <td class="tdedita">
                    <a href="<c:url value='/usuarios/${usuario.id}'/>">Editar</a>
                    <a href="javascript:;" class="deletarProduto" data-href="<c:url value='/usuario/remove?usuario.id=${usuario.id}'/>" >Deletar</a>
                </td>                    
            </tr>
        </c:forEach>    
    </tbody>
</table>

OBS.: O problema está na tabela, a cada refresh ela some e volta com o usuário cadastrado, o problema ocorre em todas as tabelas do meu projeto.

????????????????????

Olhei o código e não vi o erro. Acho que o único jeito aí é você compartilhar o código . Você faz o redirect correto e tudo mais...

Amigo, aqui está o link do meu projeto.

Aguardo seu retorno.

Opa, baixei seu código e executei o projeto. Consegui alterar o usuário normalmente, executei vários refreshes e realmente não percebi nenhum problema.

Assim que starta o projeto funciona como o esperado, porém, com o tempo o problema aparece, depois de realizar algumas modificações e o projeto ficar aberto por um tempo executando as funcionalidades.

Estou tendo este problema já tem bastante tempo, testei em vários computadores e em navegadores diferentes.

Quer que eu grave um vídeo? Tem como você revisar o código de configuração?

Opa Thiago, olha, eu revisei bastante e usei por bastante tempo. Pode gravar o video sim, vamos ver se escapou algo.

Thiago, no UsuarioDao::adiciona você não precisa executar o manager.close() no finally do try/catch?

Provavelmente (já que você não compartilhou essa parte do código) seu método de remover está bem semelhante ao de adicionar. Aí o que acontece? tem um catch com rollback. Como tem uma transação aberta, ele lança uma exceção ao tentar abrir uma nova transação e dá um rollback. Mas não fecha, aí na próxima vez que você pega o manager e tenta abrir uma transação ele identifica que o o manager ainda está aberto com um rollback e lança uma exceção e tenta dar outro rollback.

Parece ser algo assim que está acontecendo.

Removi todos os roolback e o problema conticua ocorrendo. O que eu devo fazer ???

Oi Thiago,

estou com o seu projeto rodando, mas aquele seu problema só consegui reproduzir uma vez até agora. Ainda não descobri qual é a razão para tal :(

A única coisa que percebi que o banco realmente inseriu o novo registro e que também não está acontecendo nenhuma exceção "maluca".

Vou continuar procurando mas de qq forma aconselho usar um pool de conexão.

Outro ponto é que a propriedade hibernate.dialect está errada no seu persistence.xml:

Você usou:

<property name="hibernate.dealect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />

Deve ser:

<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />

Não vamos desistir :)

Abs

solução!

Oi Thiago,

Tem como testar o seu projeto com o pom.xml e persistence.xml abaixo?

Vou te passar os arquivos (basicamente atualizei as bibliotecas e configurei o pool c3p0):

pom.xml

persistence.xml

Não vamos desistir nunca :)

abs

Nico concertei o pom.xml e até então o erro sumiu. Estou testando pra ver se vai bugar mais uma vez e assim que tiver certeza que o erro foi corrigido eu marco sua resposta como solução.

Desde já fico grato pela ajuda, foi muito útil.