[RESOLVIDO] Hibernate + JSF + Filtros web

OBS: Na verdade não resolvi, mas fazer o OSIV com PhaseListener foi bem melhor diminui os erros estranho, descobri que alguns realmente vieram de funções feitas nos objetos q acabam buscando mais itens no banco. E realmente listas (mas essas contornadas com batch size)

Eu tenho uma aplicação “legada”, que faz uso do “Open Session In View” utilizando o seguinte filtro no web.xml

<filter> <filter-name>conexaoFilter</filter-name> <filter-class>br.gov.sp.indaiatuba.koch.util.filter.ConexaoHibernateFilter</filter-class> </filter> <filter-mapping> <filter-name>conexaoFilter</filter-name> <url-pattern>*.jsf</url-pattern> </filter-mapping>

e eu tenho outros filtros no meu web.xml e por algum erro q eu não sei qual seja são 8 filtros e algumas atualizações de tela geram 8 selects no banco…

segue meu filtro de OSIV o ConexaoHibernateFilter

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.hibernate.SessionFactory;
import br.gov.sp.indaiatuba.koch.util.HibernateUtil;

public class ConexaoHibernateFilter implements Filter {
	private SessionFactory sf;
	public void destroy() {
	}
	public void doFilter(ServletRequest servletRequest,
			ServletResponse servletResponse, FilterChain chain)
			throws IOException, ServletException {
		try {
			this.sf.getCurrentSession().beginTransaction();
			chain.doFilter(servletRequest, servletResponse);
			this.sf.getCurrentSession().getTransaction().commit();
		} catch (Throwable e) {
			try {
				if (this.sf.getCurrentSession().getTransaction().isActive()) {
					this.sf.getCurrentSession().getTransaction().rollback();
				}
			} catch (Throwable t) {
				t.printStackTrace();
			}
			throw new ServletException(e);
		} finally {
			this.sf.getCurrentSession().close();
		}
	}
	public void init(FilterConfig config) throws ServletException {
		this.sf = HibernateUtil.getSessionFactory();
	}
}

como posso fazer pra que o hibernate não faça 8 selects desnecessários? eu estou usando de forma errada?

Se você deixar 1 filtro apenas, o número de consultas diminui?

Esse erro, por acaso, acontece quando você tenta acessar uma Lista Lazy?

quero acompanhar a resposta também, temos esse mesmo problema aqui, para cada filter gera uma query, com ou sem lazy

Se eu deixar 1 filtro (hipoteticamente alguns não podem ser retirados pois o sistema não funciona) mas pra cada um q eu tiro diminui as query geradas e sim como o fabiozanardi disse com ou sem lazy é o mesmo resultado

[quote=direisc]Eu tenho uma aplicação “legada”, que faz uso do “Open Session In View” utilizando o seguinte filtro no web.xml

<filter> <filter-name>conexaoFilter</filter-name> <filter-class>br.gov.sp.indaiatuba.koch.util.filter.ConexaoHibernateFilter</filter-class> </filter> <filter-mapping> <filter-name>conexaoFilter</filter-name> <url-pattern>*.jsf</url-pattern> </filter-mapping>

e eu tenho outros filtros no meu web.xml e por algum erro q eu não sei qual seja são 8 filtros e algumas atualizações de tela geram 8 selects no banco…

segue meu filtro de OSIV o ConexaoHibernateFilter

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.hibernate.SessionFactory;
import br.gov.sp.indaiatuba.koch.util.HibernateUtil;

public class ConexaoHibernateFilter implements Filter {
	private SessionFactory sf;
	public void destroy() {
	}
	public void doFilter(ServletRequest servletRequest,
			ServletResponse servletResponse, FilterChain chain)
			throws IOException, ServletException {
		try {
			this.sf.getCurrentSession().beginTransaction();
			chain.doFilter(servletRequest, servletResponse);
			this.sf.getCurrentSession().getTransaction().commit();
		} catch (Throwable e) {
			try {
				if (this.sf.getCurrentSession().getTransaction().isActive()) {
					this.sf.getCurrentSession().getTransaction().rollback();
				}
			} catch (Throwable t) {
				t.printStackTrace();
			}
			throw new ServletException(e);
		} finally {
			this.sf.getCurrentSession().close();
		}
	}
	public void init(FilterConfig config) throws ServletException {
		this.sf = HibernateUtil.getSessionFactory();
	}
}

como posso fazer pra que o hibernate não faça 8 selects desnecessários? eu estou usando de forma errada?[/quote]

Mas aí depende de como estão agindo os outros filtros? não entendi muito bem, se você migrar de filtros para PhaseListener?

Ok vou tentar explicar melhor, quando eu entro em uma pagina que faz buscas pelo bean de alguns argumentos e gera selects ao invez do select ser executado uma vez como se espera ele executa n vezes, sendo n o numero de filtros no web.xml… vou mandar meu web.xml pode ser q eu tenha feito algo de errado.

[code]<?xml version="1.0" encoding="UTF-8"?>

<display-name>Koch</display-name>

<welcome-file-list>
	<welcome-file>index.html</welcome-file>
</welcome-file-list>

<context-param>
	<param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
	<param-value>-1</param-value>
</context-param>

<context-param>
	<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
	<param-value>client</param-value>
</context-param>

<servlet>
	<servlet-name>Faces Servlet</servlet-name>
	<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
	<servlet-name>Faces Servlet</servlet-name>
	<url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<filter>
	<filter-name>conexaoFilter</filter-name>
	<filter-class>br.gov.sp.indaiatuba.koch.util.filter.ConexaoHibernateFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>conexaoFilter</filter-name>
	<url-pattern>*.jsf</url-pattern>
</filter-mapping>

<filter>
	<filter-name>springSecurityFilterChain</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	<filter-name>springSecurityFilterChain</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
	<filter-name>loginFilter</filter-name>
	<filter-class>br.gov.sp.indaiatuba.koch.util.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>loginFilter</filter-name>
	<url-pattern>*.jsf</url-pattern>
</filter-mapping>

<!-- Listener do Spring -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Local do arquivo de configuração -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		/WEB-INF/applicationContext.xml
  		/WEB-INF/applicationContext-security.xml
	</param-value>
</context-param>

<!-- Filtro para encoding nas páginas -->
<filter>
	<filter-name>Character Encoding Filter</filter-name>
	<filter-class>br.gov.sp.indaiatuba.koch.util.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>Character Encoding Filter</filter-name>
	<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

[/code]

IgorDutra eu até tentei implentar o OpenSessionInView usando PhaseListener seguindo esse tutorial porem sem sucesso… http://www.jroller.com/HazemBlog/entry/implementing_hibernate_open_session_per
a aplicação nem sobe no servidor JBOSS 7.1.1

realmente estou com problemas não é de hoje mas esta muito dificil entneder do porque.
se alguem puder dar uma analizada eu ja coloquei o web.xml com os famigerados filtros, não sei necessáriamente porque esse comportamento na aplicação.

OK mexendo feito um desesperado literalmente falando cheguei a conclusão que não são os filtros que fazer executar n vezes os selects deve ser outra coisa.

fiz umas mudanças e tirei uns filtros que pareceram desnecessários segue meu web.xml pra conferir

[code]<?xml version="1.0" encoding="UTF-8"?>

<display-name>Koch</display-name>

<servlet>
	<servlet-name>Faces Servlet</servlet-name>
	<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>Faces Servlet</servlet-name>
	<url-pattern>*.jsf</url-pattern>
</servlet-mapping>

<welcome-file-list>
	<welcome-file>index.html</welcome-file>
</welcome-file-list>

<context-param>
	<param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
	<param-value>-1</param-value>
</context-param>
<context-param>
	<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
	<param-value>client</param-value>
</context-param>

<filter>
	<filter-name>springSecurityFilterChain</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
	<filter-name>springSecurityFilterChain</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Listener do Spring -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Local do arquivo de configuração -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>
		/WEB-INF/applicationContext.xml
  		/WEB-INF/applicationContext-security.xml
	</param-value>
</context-param>

<!-- Filtro para encoding nas páginas -->
<filter>
	<filter-name>Character Encoding Filter</filter-name>
	<filter-class>br.gov.sp.indaiatuba.koch.util.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>Character Encoding Filter</filter-name>
	<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

[/code]

Retirei o OpenSessionInView dos filtros e implementei com base em PhaseListener, ficou mais preciso porem o problema dos multiplos selects continuam, ele é “aleatorio” há consultas que executam as 8 vezes e consultas q fazem menos… antes que alguem pergunte não essas consultas não tem coleções envolvidas.

esses selects estão tornando meu sistema extremamente lento eu gostaria de saber se existe algum modo de não executar tantas vezes quanto executa hoje.

Se alguem passa por esse problema e encontrou soluções elas seriam muito bem vindas.

Cara,certeza que não são os filtros que estão ocasionando esse comportamento,isso é um ‘bug’ conhecido do JSF,o que vc pode fazer é implementar algo do tipo:

 public List getLista(){
    if(lista==null)carregaLista():

}

[quote=raf4ever]Cara,certeza que não são os filtros que estão ocasionando esse comportamento,isso é um ‘bug’ conhecido do JSF,o que vc pode fazer é implementar algo do tipo:

[code]
public List getLista(){
if(lista==null)carregaLista():

}
[/code][/quote]Eu só prefiro não falar ‘bug’. Eu vejo mais pau de utilização mesmo, infelizmente o JSF é muito mau visto por muitas pessoas, pessoas essas que nunca pararam para estudar sobre JSF.

Desculpem reviver esse tópico,

Mas já que você está utilizando spring, porque não delega a ele a tarefa de criação e gerenciamento de transações? Isso livra sua camada web (Managed Beans/Filters) de ter que lidar com session/entitymanager. Mas para isso você precisa de uma camada ‘service’ em seu sistema, algo assim:

  • web (managed beans)
  • service (classes que contem a logica de negócio, gerenciada pelo spring)
  • dao
  • dominio

Sua classe service seria assim, por exemplo:

@Service
@Scope("prototype")
public class UsuarioService {

      @PersistenceContext
      private EntityManager em;

      private List<Usuario> all = new ArrayList<Usuario>();

      @Transactional
      public void loadAll() {
            all = new UsuarioDAO(em).findAll();
      }

     //getters e setters
}

E então em seus managed beans, não instancie a classe service, mas chame-a através do container do spring, para que ela venha com as devidas dependencias (injeção do entitymanager/session e o controle de transação) resolvidas:

@ManagedBean
@RequestScoped
public class UsuarioMB {
private UsuarioService service;

    @PostConstruct
    public void init(){
        service = (UsuarioService)SpringContainer.getService(UsuarioService.class);
        service.loadAll();
    }

    //getters e setters

}

Classe utilitária:

public class SpringContainer {
    public static Object getService(Class clazz){
        return FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance()).getBean(clazz);
    }
}

E então de seus .xhtml, você pode acessar diretamente os atributos de service, por exemplo uma tabela do primefaces contendo os usuários:

<p:dataTable var="loop" value="#{usuarioMB.service.all}">
      <!-- colunas -->
</p:dataTable>

Essa estratégia te livra do OSIN e te dá um bom controle nas operações com o banco de dados.

att,
Gustavo