Problemas com hibernate fazendo update indevido

15 respostas
Marcelo_Magalhaes

Tenho uma aplicação WEB usando JBOSS 7.1.1 AS, JPA (hibernate do JBOSS), JSF e acesso via JAAS. Depois da validação do login via JAAS faço o redirecionamento para uma página simples que deveria exibir os dados do usuário logado. Contudo quando executo o find para recuperar o usuário logado o hibernate faz um update do objeto que acabei de recuperar (ver console abaixo).

Trecho de código executado no meu bean

...
    @EJB
    private UsuarioDAO usuarioService;

    // ******************** Atributos ********************

    private Usuario usuario;
    private String imagem = "119.jpg";

    public Usuario getUsuario()
    {
	if(usuario == null)
	{
		ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
		String username = context.getUserPrincipal().getName();
		
		usuario = usuarioService.findUserByUsername(username); // <<<< AQUI!!!
	}
	
	return usuario;
    }
...

Saída da console do Eclipse

17:59:09,557 INFO  [stdout] (http-localhost-127.0.0.1-8080-2) Hibernate: 
17:59:09,561 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)     SELECT
17:59:09,565 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         * 
17:59:09,568 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)     FROM
17:59:09,571 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         Usuario u 
17:59:09,575 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)     WHERE
17:59:09,578 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         u.username = 'marcelo.magalhaes';

17:59:09,951 INFO  [stdout] (http-localhost-127.0.0.1-8080-2) Hibernate: 
17:59:09,954 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)     update
17:59:09,958 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         usuario 
17:59:09,961 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)     set
17:59:09,965 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         ativo=?,
17:59:09,968 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         id_classificacaoProfissional=?,
17:59:09,973 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         dataAdmissao=?,
17:59:09,976 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         dataDemissao=?,
17:59:09,980 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         id_disciplina=?,
17:59:09,984 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         email=?,
17:59:09,988 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         id_faixaSalarial=?,
17:59:09,992 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         matricula=?,
17:59:09,996 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         nome=?,
17:59:09,999 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         password=?,
17:59:10,003 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         username=? 
17:59:10,006 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)     where
17:59:10,010 INFO  [stdout] (http-localhost-127.0.0.1-8080-2)         id=?

UsuarioDAO

...
    public Usuario findUserByUsername(String username)
    {
	Map<String, Object> parameters = new HashMap<String, Object>();
	
	parameters.put("username", username);

	return (Usuario) super.retrieveByNamedQueryWithOneResult(Usuario.FIND_BY_USERNAME, parameters); <= SELECT + UPDATE
	
	//return (Usuario) super.findByNativeQuery("SELECT * FROM Usuario u WHERE u.username = '" + username + "';", Usuario.class).get(0); <= SÓ O SELECT
    }
...

Usuario (objeto)

...
@NamedQuery(name = "Usuario.findUserByUsername", query = "SELECT u FROM Usuario u WHERE u.username = :username")
...

Página JSF user.hxtml

...
	<h:body> 
		<h:graphicImage value="images/#{usuarioManagedBean.imagem}" title="Marcelo" />
		
		<p:outputLabel value="#{usuarioManagedBean.usuario.nome}" /><br/>
		<p:outputLabel value="#{usuarioManagedBean.usuario.id}" /><br/>
        <p:outputLabel value="#{usuarioManagedBean.usuario.ativo}" /><br/>
        <p:outputLabel value="#{usuarioManagedBean.usuario.username}" /><br/>
        <p:outputLabel value="#{usuarioManagedBean.usuario.password}" /><br/>
        <p:outputLabel value="#{usuarioManagedBean.usuario.matricula}" /><br/>
        <p:outputLabel value="#{usuarioManagedBean.usuario.nome}" /><br/>
        <p:outputLabel value="#{usuarioManagedBean.usuario.email}" /><br/>
        <p:outputLabel value="#{usuarioManagedBean.usuario.dataAdmissao}">
        	<f:convertDateTime pattern="dd/MM/yyyy" />
 	</p:outputLabel><br/>
        <p:outputLabel value="#{usuarioManagedBean.usuario.dataDemissao}">
        	<f:convertDateTime pattern="dd/MM/yyyy" />
 	</p:outputLabel><br/>
    
	</h:body>
...

P.S. não se preocupem com os nome trocados DAO e Service… é que antes o projeto não tinha DAOs os Services é que fazia a parte de SQL… estou adicionando a camada de DAO (que na verdade era o meu antigo Servcice).

Não sei o que está acontecendo… quando faço o SQL nativo (ver linha comentada no DAO) tudo funciona ok. E tem mais… ele executa este select + update 10 vezes que são a quantidade de atributos do meu objeto usuário. Já teste reduzir os atributos e ele reduz os selects… isso pode ser devido ao fato do bean ser RequestScoped… ele está fazendo um request para cada atributo do págins JSF.

Abraços a todos.

15 Respostas

Hebert_Coelho

E o que esse cara aqui faz?
retrieveByNamedQueryWithOneResult

Marcelo_Magalhaes

Hebert Coelho:
E o que esse cara aqui faz?
retrieveByNamedQueryWithOneResult

É justamente onde faço a consulta (getSingleResult). Código abaixo:

...
    public T retrieveByNamedQueryWithOneResult(String namedQueryName, Map<String, Object> parameters)
    {
	Query query = this.em.createNamedQuery(namedQueryName);

	for (Entry<String, Object> entry : parameters.entrySet())
	{
	    query.setParameter(entry.getKey(), entry.getValue());
	}

	return (T) query.getSingleResult();
    }
...
Hebert_Coelho

Veja se te ajuda: https://forum.hibernate.org/viewtopic.php?t=979630&start=0&postdays=0&postorder=asc&highlight=

Marcelo_Magalhaes

Amanha vou averiguar meu código con base no seu link. Post a resposta o mais onfo sobre o assunto. Obrigado uaibert… Agora me lembrei do seu blog… Esse sistema que estou cruando teve como embriam o seu exemplo do cadastro de cachorro… Grande!!! Legal.

Abraços.

Hebert_Coelho

Amanha vou averiguar meu código con base no seu link. Post a resposta o mais onfo sobre o assunto. Obrigado uaibert… Agora me lembrei do seu blog… Esse sistema que estou cruando teve como embriam o seu exemplo do cadastro de cachorro… Grande!!! Legal.

Abraços.
Estamos aí para tentar ajuda mano! =D

Qualquer coisa é só falar! \o_

Marcelo_Magalhaes

Amanha vou averiguar meu código con base no seu link. Post a resposta o mais onfo sobre o assunto. Obrigado uaibert… Agora me lembrei do seu blog… Esse sistema que estou cruando teve como embriam o seu exemplo do cadastro de cachorro… Grande!!! Legal.

Abraços.
Estamos aí para tentar ajuda mano! =D

Qualquer coisa é só falar! \o_

Achei o problema do update!!! Estava setando a senha já criptografando-a (veja o SETs abaixo comentado). E fazia o mesmo no construtor padrão do objeto Usuario.

@Size(min = 5, max = 100)
    @Column(name = "password", nullable = false, columnDefinition = "VARCHAR(100)")
    public String getPassword()
    {
	return password;
    }
    public void setPassword(String password)
    {
	//this.password = Util.createPasswordHash("SHA-256", "BASE64", null, null, password);
	this.password = password;
    }

Quando removi a criptografia da senha no setPassword tudo funcionou. O post do link enviado foi bem direto…

Contudo ainda estou com o problema de 10 selects para poder recuperar o objeto. Acho que isso tem haver com estar “perdendo a sessão” entre os selects… não sei!!! Já troquei para escopo de sessão os bean de Login e Usuario mas nada… :shock: :shock:

Pode me dar uma luz :idea:

Abraços

Hebert_Coelho

Marcelo Magalhaes:
Contudo ainda estou com o problema de 10 selects para poder recuperar o objeto. Acho que isso tem haver com estar “perdendo a sessão” entre os selects… não sei!!! Já troquei para escopo de sessão os bean de Login e Usuario mas nada… :shock: :shock:

Pode me dar uma luz :idea:

Abraços

Será que você não tem um get que está disparnado essa consulta muitas vezes não?

Marcelo_Magalhaes

Hebert Coelho:
Marcelo Magalhaes:
Contudo ainda estou com o problema de 10 selects para poder recuperar o objeto. Acho que isso tem haver com estar “perdendo a sessão” entre os selects… não sei!!! Já troquei para escopo de sessão os bean de Login e Usuario mas nada… :shock: :shock:

Pode me dar uma luz :idea:

Abraços

Será que você não tem um get que está disparnado essa consulta muitas vezes não?

O loop está ocorrendo neste trecho de código no bean da página que exibi os dados do usuário conectado.

...
 public Usuario getUsuario()  
    {  
    if(usuario == null)  
    {  
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();  
        String username = context.getUserPrincipal().getName();  
          
        usuario = usuarioService.findUserByUsername(username); // <<<< AQUI!!!  
    }  
      
    return usuario;  
    }  
...

Mas este trecho só deveria ser executado uma vez que a página fosse renderizada. Ou seja a página (abaixo) solicita 10 vezes um get no objeto usuário… e o bean somente deveria fazer isso uma vez, na segunda vez o objeto usuário não seria null, mas está sendo???

...
...  
    <h:body>   
        <h:graphicImage value="images/#{usuarioManagedBean.imagem}" title="Marcelo" />  
          
        <p:outputLabel value="#{usuarioManagedBean.usuario.nome}" /><br/>  
        <p:outputLabel value="#{usuarioManagedBean.usuario.id}" /><br/>  
        <p:outputLabel value="#{usuarioManagedBean.usuario.ativo}" /><br/>  
        <p:outputLabel value="#{usuarioManagedBean.usuario.username}" /><br/>  
        <p:outputLabel value="#{usuarioManagedBean.usuario.password}" /><br/>  
        <p:outputLabel value="#{usuarioManagedBean.usuario.matricula}" /><br/>  
        <p:outputLabel value="#{usuarioManagedBean.usuario.nome}" /><br/>  
        <p:outputLabel value="#{usuarioManagedBean.usuario.email}" /><br/>  
        <p:outputLabel value="#{usuarioManagedBean.usuario.dataAdmissao}">  
            <f:convertDateTime pattern="dd/MM/yyyy" />  
        </p:outputLabel><br/>  
        <p:outputLabel value="#{usuarioManagedBean.usuario.dataDemissao}">  
            <f:convertDateTime pattern="dd/MM/yyyy" />  
        </p:outputLabel><br/>  
      
    </h:body>
...

Abraços.

Hebert_Coelho

Qual o escopo desse MB?

Marcelo_Magalhaes

Session ou Request da no mesmo?! :shock:

Hebert_Coelho

Session ou Request da no mesmo?! :shock: Estranho isso. Ele está encontrando o usuário? Debug ai para ver se não está exibindo mensagem de erro.

Marcelo_Magalhaes

Session ou Request da no mesmo?! :shock: Estranho isso. Ele está encontrando o usuário? Debug ai para ver se não está exibindo mensagem de erro.

Acho que o problema está no método getUsuario() do bean…não sei o que mas estou sismado neste ponto… enfim mudei o código para carregar o usuário do banco de dados quando o bean é instanciado (coloquei no construtor), ver código abaixo. Agora o problema é que quando chega na linha de executar o findUserByUsername() o meu serviço (que por enquanto se chama UsuarioDAO) está null… isso está estranho porque no getUsuario() ele não está null… só fiz foi mudar o código que carrega o usuário de lugar… saiu do getUsuario() e foi para o construtor da classe.

...
    @EJB
    private UsuarioDAO usuarioService;

    // ******************** Atributos ********************

    private Usuario usuario;
    private String imagem = "119.jpg";

    public UsuarioManagedBean()
    {
	ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
	String username = context.getUserPrincipal().getName();
	
	usuario = usuarioService.findUserByUsername(username); <<<< Aqui o usuarioService está NULL!!!
    }
...

Abraços,

Hebert_Coelho

Você sabe que não se deve colocar método em construtor?

Crie um método e anote com @PostConstruct

Marcelo_Magalhaes

Hebert Coelho:
Você sabe que não se deve colocar método em construtor?

Crie um método e anote com @PostConstruct

Foi!!! Tudo certo. A minha desconfiança daquele método getUsuario estava certa… por alguma razão ele sempre colocava o usuário null e ficava chamando diversas vezes (quantidade de atributos).

Agora a questão do construtor achava que era boa prática não se colocar código dentro deles… mas seguindo seu conselho funcionou, o serviço é injeto perfeitamente e o método de pesquisa no BD é executado somente uma vez. Você sabe o por que o CDI não injeta o em u serviço no bean no construtor do mesmo??? Isso é alguma limitação do CDI ou é assim mesmo???

Abraços e muito obrigado pela ajuda! :lol:

Hebert_Coelho

Marcelo Magalhaes:
Hebert Coelho:
Você sabe que não se deve colocar método em construtor?

Crie um método e anote com @PostConstruct

Foi!!! Tudo certo. A minha desconfiança daquele método getUsuario estava certa… por alguma razão ele sempre colocava o usuário null e ficava chamando diversas vezes (quantidade de atributos).

Agora a questão do construtor achava que era boa prática não se colocar código dentro deles… mas seguindo seu conselho funcionou, o serviço é injeto perfeitamente e o método de pesquisa no BD é executado somente uma vez. Você sabe o por que o CDI não injeta o em u serviço no bean no construtor do mesmo??? Isso é alguma limitação do CDI ou é assim mesmo???

Abraços e muito obrigado pela ajuda! :lol:

É como funciona. [=
Construtor não é confiável. [=

Criado 28 de janeiro de 2013
Ultima resposta 30 de jan. de 2013
Respostas 15
Participantes 2