[Resolvido] Primefaces 3.4.1 - dataTable com paginação muito lenta
41 respostas
K
Kleber-rr
Boa noite a todos.
Estou utilizando esta versão de primefaces e estou com um problema no dataTable. Na mudança de página do resultado, ele demora muito a atualizar o dataTable, como se fosse feita a consulta novamente.
Aguem já passou por isso?
Minha base de dados é grande (banco de cep dos correios). Poderia ser esse o motivo?
Você está fazendo a consulta paginada? Ou simplesmente executa a consulta uma vez e joga a lista no datatable?
G
grinche
Se você estiver utilizando a propriedade Lazy com o valor true no seu datatable sempre que você alterar a página ele faz uma nova requisição ao servidor e vai ao banco de dados buscar as informações. Caso esta propriedade tenha o valor false, todas informações já são carregadas e a lentidão é apenas no lado cliente pois tudo é feito por javascript.
K
Kleber-rr
Olá Herbert, bom dia.
Executo a consulta uma única vez preenchendo a lista no dataTable.
H
Hebert_Coelho
grinche:
Se você estiver utilizando a propriedade Lazy com o valor true no seu datatable sempre que você alterar a página ele faz uma nova requisição ao servidor e vai ao banco de dados buscar as informações. Caso esta propriedade tenha o valor false, todas informações já são carregadas e a lentidão é apenas no lado cliente pois tudo é feito por javascript.
Sério? Eu achava que isso dependia da configuração de estado que se encontra no web.xml. Até onde eu sei, se o estado estiver servidor os dados ficam alocados no httpSession; caso o estado esteja cliente, aí sim ficaria salvo lá.
Vou pesquisar melhor sobre isso viu.
H
Hebert_Coelho
Olá Herbert, bom dia.
Executo a consulta uma única vez preenchendo a lista no dataTable.E quantos registros estão voltando?
K
Kleber-rr
Obrigado pela resposta.
Não estou instanciando a propriedade Lazy. Mas com certeza, ele refaz a pesquisa a cada mudança de pagina, independente da quantidade de resultados retornados. Pode ser 10 resultados ou 100, o tempo é o mesmo.
H
Hebert_Coelho
Obrigado pela resposta.
Não estou instanciando a propriedade Lazy. Mas com certeza, ele refaz a pesquisa a cada mudança de pagina, independente da quantidade de resultados retornados. Pode ser 10 resultados ou 100, o tempo é o mesmo.
Mas para saber isso, você não pode ir pelo tempo. Você tem que debugar, ou colocar mensagens para exibir no console.
K
Kleber-rr
Olá Herbert, bom dia.
Executo a consulta uma única vez preenchendo a lista no dataTable.E quantos registros estão voltando?
Herbert, se voltar registros que dêem mais de 1 página, o tempo é o mesmo. Ou seja, se eu clicar na página 2/2 ele demora o mesmo tempo de se eu clicar na página 2/100.
Vou dar uma olhada novamente no web.xml pra ver o estado.
A tarde respondo, pq não estou com o projeto aqui.
Obrigado pela ajuda.
H
Hebert_Coelho
Olá Herbert, bom dia.
Executo a consulta uma única vez preenchendo a lista no dataTable.E quantos registros estão voltando?
Herbert, se voltar registros que dêem mais de 1 página, o tempo é o mesmo. Ou seja, se eu clicar na página 2/2 ele demora o mesmo tempo de se eu clicar na página 2/100.
Vou dar uma olhada novamente no web.xml pra ver o estado.
A tarde respondo, pq não estou com o projeto aqui.
Obrigado pela ajuda.Novamente, tempo não é parâmetro para se deduzir isso…
K
Kleber-rr
Obrigado pela resposta.
Não estou instanciando a propriedade Lazy. Mas com certeza, ele refaz a pesquisa a cada mudança de pagina, independente da quantidade de resultados retornados. Pode ser 10 resultados ou 100, o tempo é o mesmo.
Mas para saber isso, você não pode ir pelo tempo. Você tem que debugar, ou colocar mensagens para exibir no console.
Blz.
Um comportamento que eu achei estranho, já que sempre coloco os benditos System.out.println pra saber o que anda acontecendo, é que, quando a consulta é realizada e por exemplo, no início do método que preenche o dataTable eu coloco um System.out.println para ele me imprimir no console o nome do campo preenchido na página, no console ele me exibe a resposta do System.out.println várias vezes, e não uma só, por exemplo:
public List<Endereco> getCEP() {
String campo = this.campoBusca;
System.out.println ("campo: " + campo);
...
Sei que a pergunta pode parecer ignorante, mas me intrigou:
Só pelo fato de eu colocar o nome do método iniciando com get ele chama diversas vezes?
Eu faço uma verificação de conteudo nulo sim dentro de um if e ele só executa a consulta se o conteúdo não for null ou não for empty.
Não.
O método ele é chamado por que na tela (xhtml/jsp) tem algum componente apontando para o método. O JSF precisa fazer várias verificações/utilizações e o primefaces também.
G
grinche
Nunca popule um objeto dentro do método get, pois a cada requisição feita ao seu ManagedBean ele vai entrar no método get.
Crie uma propriedade no seu ManagedBean e também um método que vai popular este objeto, anote este método como PostConstruct, e então popule este e outros objetos neste método “inicial”. http://docs.oracle.com/javaee/5/api/javax/annotation/PostConstruct.html
Ou no seu xhtml utilize este evento para chamar um método que popula esta sua propriedade do managedBean.
Sei que a pergunta pode parecer ignorante, mas me intrigou:
Só pelo fato de eu colocar o nome do método iniciando com get ele chama diversas vezes?
Eu faço uma verificação de conteudo nulo sim dentro de um if e ele só executa a consulta se o conteúdo não for null ou não for empty.
Não.
O método ele é chamado por que na tela (xhtml/jsp) tem algum componente apontando para o método. O JSF precisa fazer várias verificações/utilizações e o primefaces também.
Mas na xhtml o método esta instanciado em um commandButton, então entendo que ele só é executado quando acionado. Estou correto?
G
grinche
Não! Todo método que inicia com o nome get vai ser chamado a cada requisição.
K
Kleber-rr
grinche:
Não! Todo método que inicia com o nome get vai ser chamado a cada requisição.
Bom, vou testar então mudando o nome do método pra ver se ele é acionado + de 1 vez na requisição.
G
grinche
São os ciclos de vida do jsf, ele vai acessas seus métodos get várias vezes.
De uma olhada neste link abaixo, que você vai entender melhor.
http://gustavopinto.wordpress.com/tag/jsf/
H
Hebert_Coelho
grinche:
Nunca popule um objeto dentro do método get, pois a cada requisição feita ao seu ManagedBean ele vai entrar no método get.
Crie uma propriedade no seu ManagedBean e também um método que vai popular este objeto, anote este método como PostConstruct, e então popule este e outros objetos neste método “inicial”. http://docs.oracle.com/javaee/5/api/javax/annotation/PostConstruct.html
Ou no seu xhtml utilize este evento para chamar um método que popula esta sua propriedade do managedBean.
Não é uma boa idéia ser tão radical.
Já ouviu falar de lazy get? Você colocando no @PostConstruct toda vez que o MB for criado a consulta será executada mesmo que não venha a ser necessária.
O Lazy get funciona como eu postei acima, utilizando um if(atributo == null). Desse modo você irá executar apenas uma vez, pois após a primeira vez o atributo já estará populado.
Existe realmente as duas abordagens. Cada uma tem sua vantagem e desvantagem, mas nenhuma não deve ser taxada como “NOT TO USE”.
K
Kleber-rr
grinche:
São os ciclos de vida do jsf, ele vai acessas seus métodos get várias vezes.
De uma olhada neste link abaixo, que você vai entender melhor.
http://gustavopinto.wordpress.com/tag/jsf/
Obrigado man. Vou dar uma olhada e a tarde eu posto o resultado.
Flws.
G
grinche
Hebert Coelho:
grinche:
Nunca popule um objeto dentro do método get, pois a cada requisição feita ao seu ManagedBean ele vai entrar no método get.
Crie uma propriedade no seu ManagedBean e também um método que vai popular este objeto, anote este método como PostConstruct, e então popule este e outros objetos neste método “inicial”. http://docs.oracle.com/javaee/5/api/javax/annotation/PostConstruct.html
Ou no seu xhtml utilize este evento para chamar um método que popula esta sua propriedade do managedBean.
Não é uma boa idéia ser tão radical.
Já ouviu falar de lazy get? Você colocando no @PostConstruct toda vez que o MB for criado a consulta será executada mesmo que não venha a ser necessária.
O Lazy get funciona como eu postei acima, utilizando um if(atributo == null). Desse modo você irá executar apenas uma vez, pois após a primeira vez o atributo já estará populado.
Existe realmente as duas abordagens. Cada uma tem sua vantagem e desvantagem, mas nenhuma não deve ser taxada como “NOT TO USE”.
Com certeza, você tem razão cado caso é um caso rsrsrs
Mas acredito eu que a melhor solução para o problema dele é utilizar o evento preRenderView.
H
Hebert_Coelho
Kleber-rr:
Hebert Coelho:
Kleber-rr:
Hebert Coelho:
Cara, o get é chamado diversas vezes e não uma só.
Por isso que ta lento. Toda hora você ta disparando a consulta.
Sei que a pergunta pode parecer ignorante, mas me intrigou:
Só pelo fato de eu colocar o nome do método iniciando com get ele chama diversas vezes?
Eu faço uma verificação de conteudo nulo sim dentro de um if e ele só executa a consulta se o conteúdo não for null ou não for empty.
Não.
O método ele é chamado por que na tela (xhtml/jsp) tem algum componente apontando para o método. O JSF precisa fazer várias verificações/utilizações e o primefaces também.
Mas na xhtml o método esta instanciado em um commandButton, então entendo que ele só é executado quando acionado. Estou correto?
Entenda o seguinte. get/set é padrão de nomeclatura javabeans.
O JSF não olha e fala: “ih tem um método que começa com get. Vou invocá-lo!”
Faça um teste, crie um método chamado getNaoVouSerChamado e coloque no MB, mas em nenhum momento aponte algum componente para ele. E você verá que ele não será chamado.
H
Hebert_Coelho
grinche:
Não! Todo método que inicia com o nome get vai ser chamado a cada requisição.
Eu fiz esse teste aqui e não funciona com você disse.
Eu utilizei o Mojarra 2.1.12
Qual o cenário que você consegue criar para afirmar isso?
R
Rodrigo_Sasaki
Hebert Coelho:
grinche:
Não! Todo método que inicia com o nome get vai ser chamado a cada requisição.
Eu fiz esse teste aqui e não funciona com você disse.
Eu utilizei o Mojarra 2.1.12
Qual o cenário que você consegue criar para afirmar isso?
:shock:
Até onde eu sei, se o atributo não está setado como value (e outro detalhe, o atributo sequer precisa existir, somente os get/set são suficientes), o método não é invocado.
E nem tem por que ser.
G
grinche
Você ta certo, quis passar a mensagem de que é pra ele não usar isso e acabei falando besteira.
Sempre que tu for atualizar uma região onde tenha um elemento jsf se referenciando a uma propriedade de seu ManagedBean o método get vai ser chamado.
E no caso dele onde no seu método get ele vai a banco isso não é necessário pois ele só quer carregar na primeira vez que o usuário entrar na sua página.
H
Hebert_Coelho
grinche:
Você ta certo, quis passar a mensagem de que é pra ele não usar isso e acabei falando besteira.
Sempre que tu for atualizar uma região onde tenha um elemento jsf se referenciando a uma propriedade de seu ManagedBean o método get vai ser chamado.
E no caso dele onde no seu método get ele vai a banco isso não é necessário pois ele só quer carregar na primeira vez que o usuário entrar na sua página.
Exato.
Por isso eu falei do get com if (== null).
Bem, fica ao critério dele escolher uma abordagem.
G
grinche
Mesmo assim, acho errado fazer isso, tu vai precisar fazer uma validação a cada vez que entrar no método get.
Utilizando as outras soluções isso não é necessário.
[]'s
H
Hebert_Coelho
grinche:
Mesmo assim, acho errado fazer isso, tu vai precisar fazer uma validação a cada vez que entrar no método get.
Utilizando as outras soluções isso não é necessário.
[]'s
Como eu disse, cada abordagem tem sua vantagem e desvantagem.
SE você for entrar em uma tela que utilize o mesmo MB mas não utilize a lista. Você acha correto carregar a lista desnecessariamente?
G
grinche
Claro que não. Por isso a utilização do preRenderView no qual você so adiciona na tela em que quer carregar a lista.
H
Hebert_Coelho
grinche:
Claro que não. Por isso a utilização do preRenderView no qual você so adiciona na tela em que quer carregar a lista.
Mas se o método com postconstruct carrega 3 informações do banco de dados. Como que essa anotação vai fazer com que o método anotado com postconstruct carregue apenas a informação necessária?
G
grinche
O evento de preRenderView não é uma anotação e nem postConstruct. É um evento do jsf no qual você chama um método no seu managedbean.
Como se for um onload do body mas que te possibilita a chamar um método no managedBean antes de construir a pagina.
H
Hebert_Coelho
grinche:
Mesmo assim, acho errado fazer isso, tu vai precisar fazer uma validação a cada vez que entrar no método get.
Utilizando as outras soluções isso não é necessário.
[]'s
Então não estamos falando de @Postconstruct mais. Você falou soluções, estava trabalhando em cima dele.
grinche:
O evento de preRenderView não é uma anotação e nem postConstruct. É um evento do jsf no qual você chama um método no seu managedbean.
Como se for um onload do body mas que te possibilita a chamar um método no managedBean antes de construir a pagina.
A idéia de utilizar o f:event é legal.
Volto a dizer, é questão de gosto. [=
com o f:event você vai ter que ter um método a mais para isso, mas funciona do mesmo modo.
K
Kleber-rr
Bom, agora no computador com o projeto, vou postar o método que preenche o dataTable. Talvez, tenha algum erro nele:
Talvez?
Mano, já falei qual o erro... deu 4 páginas de discussão sobre abordagens para solucionar o seu problema...
G
grinche
Meu deus…
todos esses return e um else sem nada…
Tem muita coisa pra arrumar ai…
Faz o que nos comentamos nos topicos anteriores.
K
Kleber-rr
Calma amigos, hehehe. Estou costurando ainda esse método, por isso tem muitos retornos e elses incompletos.
Vou estudar mais e testar a sugestão de vcs. Agradeço a colaboração.
K
Kleber-rr
Valeu Pessoal. Estudando um pouco mais sobre o ciclo de vida do JSF e sobre os 10 "maus hábitos" dos desenvolvedores JSF (Rafael Ponte e Tarso Bessa) [url]http://www.slideshare.net/tarsobessa/os-10-maus-hbitos-dos-desenvolvedores-jsf[/url], pude compreender melhor o que o grinche e o Herbert Coelho estavam tentando me explicar. Vi que o problema estava na forma em que eu invocava um List com get para preencher um dataTable. Isso gerava uma carga de consulta sem necessidade.
Para ajudar os que estão com essa mesma dificuldade oriunda dos péssimos hábitos adquiridos nos cursos de JSF1.2 (eu), postarei abaixo como deverá ficar uma consulta filtrada no bean e no jsf. Aos amigos, se eu estiver errado, podem me corrigir.
Agradeço a ajuda de todos, principalmente do grinche e do Herbert Coelho.
Vlw.
K
Kleber-rr
Valeu Pessoal. Estudando um pouco mais sobre o ciclo de vida do JSF e sobre os 10 "maus hábitos" dos desenvolvedores JSF (Rafael Ponte e Tarso Bessa) [url]http://www.slideshare.net/tarsobessa/os-10-maus-hbitos-dos-desenvolvedores-jsf[/url], pude compreender melhor o que o grinche e o Herbert Coelho estavam tentando me explicar. Vi que o problema estava na forma em que eu invocava um List com get para preencher um dataTable. Isso gerava uma carga de consulta sem necessidade.
Para ajudar os que estão com essa mesma dificuldade oriunda dos péssimos hábitos adquiridos nos cursos de JSF1.2 (eu), postarei abaixo como deverá ficar uma consulta filtrada no bean e no jsf. Aos amigos, se eu estiver errado, podem me corrigir.