Estou desenvolvendo uma aplicação Java + JSF(Primefaces) + Hibernate, sendo que em determinado momento quando faço um acesso simultâneo com outro usuário ao mesmo registro ocorre um erro de [could not inspect JDBC autocommit mode]. Este erro já identifique que é devido ao tratamento no meu DAO, onde ao concluir a leitura do registro o primeiro processo fecha a sessão, sendo que o outro processo ainda está em execução. Alguém poderia me ajudar nesta solução? Como tratar esta concorrência de leitura no hibernate?
Não trabalhe com autocommit direto e implemente o FilterOpenSessionInView onde o commit e roolback são dados corretamente em um só ponto
<property name="hibernate.connection.autocommit">false</property>
`
@WebFilter(filterName = “conexaoFilter”)
public class FilterOpenSessionInView extends DelegatingFilterProxy implements
Serializable {
private static final long serialVersionUID = 1L;
private static SessionFactory sf;
@Override
public void initFilterBean() throws ServletException {
sf = HibernateUtil.getSessionFactory();
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
BasicDataSource springDataSource = (BasicDataSource) ContextLoaderListenerCaixakiUtils.getBean("springDataSource");
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(springDataSource);
TransactionStatus status = transactionManager.getTransaction(def);
try {
servletRequest.setCharacterEncoding("UTF-8");
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpSession sessao = request.getSession();
Entidade userLogadoSessao = (Entidade) sessao.getAttribute("userLogadoSessao");
if (userLogadoSessao != null) {
UtilFramework.getThreadLocal().set(userLogadoSessao.getEnt_codigo());
}
sf.getCurrentSession().beginTransaction();
chain.doFilter(servletRequest, servletResponse);
sf.getCurrentSession().getTransaction().commit();
transactionManager.commit(status);
servletResponse.setCharacterEncoding("UTF-8");
servletResponse.setContentType("text/html; charset=UTF-8");
} catch (Exception e) {
transactionManager.rollback(status);
e.printStackTrace();
if (sf.getCurrentSession().getTransaction().isActive()) {
sf.getCurrentSession().getTransaction().rollback();
}
} finally {
if (sf.getCurrentSession().isOpen()) {
if (sf.getCurrentSession().beginTransaction().isActive()) {
sf.getCurrentSession().clear();
}
sf.getCurrentSession().close();
}
}
}
}
`
Oi, Alexfe! Eu já não estava utilizando o autocommit e também não estou utilizando o Spring. Para confirmar, veja se esta abordagem que me passou realmente resolveria o problema de concorrência na leitura dos dados. Vou te passar mais informações sobre o problema:
Segue minha configuração do Hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- Conexão BD -->
<property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
<property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
<property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/dosiero_dsv</property>
<property name="hibernate.connection.username">xxxxx</property>
<property name="hibernate.connection.password">xxx</property>
<!-- Pool Conexoes -->
<property name="hibernate.hbm2ddl.auto">none</property>
<property name="hibernate.connection.autocommit">false</property>
<property name="hibernate.format_sql">false</property>
<property name="hibernate.show_sql">false</property>
<property name="current_session_context_class">thread</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="hibernate.c3p0.acquire_increment">5</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.max_statements">50</property>
<property name="hibernate.c3p0.timeout">1800</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<mapping class="_model.vo.Usuario" />
<mapping class="_model.vo.Cliente" />
<mapping class="_model.vo.Unidade" />
<mapping class="_model.vo.Classe" />
<mapping class="_model.vo.Descritor" />
<mapping class="_model.vo.Modulo" />
<mapping class="_model.vo.Perfil" />
<mapping class="_model.vo.Pagina" />
<mapping class="_model.vo.ClienteModulo" />
<mapping class="_model.vo.Acervo" />
<mapping class="_model.vo.AcervoDescritor" />
<mapping class="_model.vo.PerfilPagina" />
<mapping class="_model.vo.Documento" />
</session-factory>
Segue meu Web.xml
<?xml version="1.0" encoding="UTF-8"?> com.sun.faces.config.ConfigureListener primefaces.SUBMIT partial javax.faces.FACELETS_SKIP_COMMENTS true javax.faces.DEFAULT_SUFFIX .xhtml javax.faces.PARTIAL_STATE_SAVING true primefaces.THEME afterdark javax.faces.CONFIG_FILES /WEB-INF/faces-config.xml, /WEB-INF/faces-navigation.xml, /WEB-INF/faces-managed-beans.xml com.sun.faces.expressionFactory com.sun.el.ExpressionFactoryImpl primefaces.UPLOADER commons Resource Servlet org.primefaces.resource.ResourceServlet Faces Servlet javax.faces.webapp.FacesServlet 1 Faces Servlet *.jsf *.xhtml *.faces PrimeFaces FileUpload Filter org.primefaces.webapp.filter.FileUploadFilter thresholdSize 51200 PrimeFaces FileUpload Filter Faces Servlet 30 index.xhtml jpg image/jpegSegue a rotina de edição, que busca outras informações do objeto (Acervo) que tem uma lista de objetos (Documentos e Descritores) dentro dele. O problema ocorre exatamente quando outro usuário acessa esta mesma rotina simultaneamente e ambas tentam recuperar as informações dos subobjetos (Documentos e Descritores) abaixo em destaque:
public String editar() throws Exception
{
acervo = acervoSel;
if (acervo.getObjClasse().getClas_nr_fasecorrente()!=null && acervo.getObjClasse().getClas_nr_fasecorrente() > 0) {
acervo.getObjClasse().setClas_ds_fasecorrente(acervo.getObjClasse().getClas_nr_fasecorrente().toString() + " " + acervo.getObjClasse().getClas_tx_fasecorrente() + "(s)");
} else {
acervo.getObjClasse().setClas_ds_fasecorrente(acervo.getObjClasse().getClas_tx_fasecorrente());
}
// --- Carrega subclasses do Acervo - Documentos e Descritores
acervoManager = new AcervoManager();
// ----------------------------------------------------------------------------------------------------------------
ROTINA QUE INICIA A BUSCA AOS DADOS E GERA O PROBLEMA
// ----------------------------------------------------------------------------------------------------------------
acervo = acervoManager.carregaSubClassesDoAcervo(acervo);
// ----------------------------------------------------------------------------------------------------------------
// --- Identifica os descritores selecionados na lista de descritores.
seldescritors = new ArrayList<Descritor>();
if(acervo.getAcervoDescritors()!=null && acervo.getAcervoDescritors().size()>0) {
for (AcervoDescritor lista : acervo.getAcervoDescritors()) {
Descritor obj = new Descritor();
obj = lista.getObjDescritor();
seldescritors.add(obj);
}
}
verificaAutoMovimentacao();
return "/pages/acervo/cadacervodetalhe.xhtml";
}
Segue rotina destacada:
public Acervo carregaSubClassesDoAcervo(Acervo filtro) throws ControllerException {
HibernateUtil.getSession();
Acervo objAcervo = new Acervo();
objAcervo=filtro;
// --- Carrega Documento relacionados ao acervo
List<Documento> documentos = new ArrayList<Documento>();
List<AcervoDescritor> acervoDescritors = new ArrayList<AcervoDescritor>();
try
{
// --- ROTINA PARA BUSCAR TODOS DOCUMENTOS RELACIONADOS AO ACERVO
documentos = documentoDAO.allDocumentosAcervo(filtro);
// --- ROTINA PARA BUSCAR TODOS OS DESCRITORES RELACIONADOS AO ACERVO
acervoDescritors = acervoDescritorDAO.pesquisaAcervoDescritorPorAcervo(filtro);
// --- ATRIBUINDO AS SUBCLASSES AO ACERVO
objAcervo.setDocumentos(documentos);
objAcervo.setAcervoDescritors(acervoDescritors);
}
catch (DaoException e)
{
throw new ControllerException(e);
}
finally
{
HibernateUtil.closeSession();
}
return objAcervo;
}
Agora os DAOS respectivos:
Dao para buscar os Documentos:
public List<Documento> allDocumentosAcervo(Acervo filtro) throws DaoException {
List<Documento> paginas = new ArrayList<Documento>();
try {
StringBuffer sql = new StringBuffer("");
sql.append("select res1 from Documento as res1 ");
sql.append("where objAcervo.id = :codfiltro ");
Query query = HibernateUtil.getSession()
.createQuery(sql.toString());
query.setParameter("codfiltro", filtro.getId());
paginas = findMany(query);
} catch (Exception e) {
throw new DaoException(e);
}
return paginas;
}
Dao para buscar os Descritores:
public List<AcervoDescritor> pesquisaAcervoDescritorPorAcervo(Acervo filtro) throws DaoException {
List<AcervoDescritor> filtrodescritors = new ArrayList<AcervoDescritor>();
try {
StringBuffer sql = new StringBuffer("");
sql.append("select res1 from AcervoDescritor res1 ");
sql.append("where res1.objAcervo.id = :codfiltro ");
Query query = HibernateUtil.getSession()
.createQuery(sql.toString());
query.setParameter("codfiltro", filtro.getId());
filtrodescritors = findMany(query);
} catch (Exception e) {
throw new DaoException(e);
}
return filtrodescritors;
}
Quando o primeiro processo sai do DAO a sessão e fechada e ocorre o erro, já que o outro processo ainda esta em andamento.
Apr 13, 2016 5:43:20 PM com.sun.faces.lifecycle.InvokeApplicationPhase execute
WARNING: #{acervoView.editar()}: exception.ControllerException: exception.DaoException: org.hibernate.exception.GenericJDBCException: could not inspect JDBC autocommit mode
javax.faces.FacesException: #{acervoView.editar()}: exception.ControllerException: exception.DaoException: org.hibernate.exception.GenericJDBCException: could not inspect JDBC autocommit mode
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
at org.primefaces.application.DialogActionListener.processAction(DialogActionListener.java:45)
at javax.faces.component.UICommand.broadcast(UICommand.java:315)
at javax.faces.component.UIData.broadcast(UIData.java:1108)
at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
Muito obrigado pela ajuda!
Olhando logo de cara estou achando estranho o seu getSession, vc tem que trabalhar com transações
HibernateUtil.getCurrentSession().beginTransaction(); /*processa tudo que tem pra fazer */ HibernateUtil..getCurrentSession().getTransaction().commit();
Como eu estava apenas lendo um registro achei que não fosse necessário colocar em transações. Fiz a alteração, mas o erro continua. Segue minha classe HibernateUtil.java
public class HibernateUtil {
private static HibernateUtil instance = null;
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;
private static Session hibernateSession = null;
private static final ThreadLocal localSession = new ThreadLocal();
private static final ThreadLocal localTx = new ThreadLocal();
private HibernateUtil() throws DaoException {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
throw new DaoException(e);
}
}
public static HibernateUtil getInstance() throws DaoException {
if (instance == null) {
instance = new HibernateUtil();
}
return instance;
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void beginTransaction() {
//--hibernateSession.beginTransaction();
localTx.set(getSession().beginTransaction());
}
public static void commitTransaction() {
//--hibernateSession.getTransaction().commit();
if (localTx.get() != null)
localTx.get().commit();
}
public static void rollbackTransaction() {
// --hibernateSession.getTransaction().rollback();
if (localTx.get() != null)
localTx.get().rollback();
}
public static void closeSession() {
if(hibernateSession.isOpen()) {
hibernateSession.close();
}
}
public static Session getSession() {
try
{
if (hibernateSession == null || !hibernateSession.isOpen()) {
hibernateSession = getSessionFactory().openSession();
localSession.set(hibernateSession);
}
} catch (Exception e) {
System.out.println(e);
throw new RuntimeException(e);
}
return hibernateSession;
}
}
Segue o método com a implementação das transações:
public Acervo carregaSubClassesDoAcervo(Acervo filtro) throws ControllerException {
HibernateUtil.getSession();
Acervo objAcervo = new Acervo();
objAcervo=filtro;
// --- Carrega Documento relacionados ao acervo
List<Documento> documentos = new ArrayList<Documento>();
List<AcervoDescritor> acervoDescritors = new ArrayList<AcervoDescritor>();
try
{
HibernateUtil.beginTransaction();
/*processa tudo que tem pra fazer */
// --- ROTINA PARA BUSCAR TODOS DOCUMENTOS RELACIONADOS AO ACERVO
documentos = documentoDAO.allDocumentosAcervo(filtro);
// --- ROTINA PARA BUSCAR TODOS OS DESCRITORES RELACIONADOS AO ACERVO
acervoDescritors = acervoDescritorDAO.pesquisaAcervoDescritorPorAcervo(filtro);
HibernateUtil.commitTransaction();
// --- ATRIBUINDO AS SUBCLASSES AO ACERVO
objAcervo.setDocumentos(documentos);
objAcervo.setAcervoDescritors(acervoDescritors);
}
catch (DaoException e)
{
throw new ControllerException(e);
}
finally
{
HibernateUtil.closeSession();
}
return objAcervo;
Veja o erro que está gerando agora. Neste caso os 2(dois) computadores que acessaram o mesmo registro retornaram a tela de erro. Note nas linhas abaixo que ele dispara os dois processos que são interrompidos no passo 2, exatamente quando ele está dentro das transações.
INFO: Server startup in 6442 ms
Ocorreu outro tipo de exceção: exception.DaoException: org.hibernate.SessionException: Session is closed!
Ocorreu outro tipo de exceção: exception.DaoException: org.hibernate.exception.GenericJDBCException: could not extract ResultSet
passo 1
passo 1.2
passo 2
passo 1
passo 1.2
passo 2
Apr 14, 2016 2:58:07 PM com.sun.faces.lifecycle.InvokeApplicationPhase execute
WARNING: #{acervoView.editar()}: org.hibernate.TransactionException: nested transactions not supported
javax.faces.FacesException: #{acervoView.editar()}: org.hibernate.TransactionException: nested transactions not supported
at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
at org.primefaces.application.DialogActionListener.processAction(DialogActionListener.java:45)
pode remover esses ThreadLocal isso não da certo
Abaixo está o Hibernate utitl quer eu uso em todos os projetos
`public class HibernateUtil implements Serializable {
private static SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
if (sessionFactory == null ) {
sessionFactory = (new Configuration()).configure()
.buildSessionFactory();
}
return sessionFactory;
} catch (Exception e) {
e.printStackTrace();
throw new ExceptionInInitializerError(
"Erro ao criar conexгo SessionFactory");
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getCurrentSession() {
return getSessionFactory().getCurrentSession();
}
public static Session openSession() {
if (sessionFactory == null)
buildSessionFactory();
return sessionFactory.openSession();
}
}`
Oi Alexfe! A coisa aqui está desigual. Java 10 x 1. De qualquer forma quero te agradecer a ajuda! Fiz uma alteração no meu HibernateUtil e acho que o problema foi superado.
Segue a classe modificada:
public class HibernateUtil {
private static HibernateUtil instance = null;
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;
private static Session hibernateSession = null;
private static final ThreadLocal session = new ThreadLocal();
private HibernateUtil() throws DaoException {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
throw new DaoException(e);
}
}
public static HibernateUtil getInstance() throws DaoException {
if (instance == null) {
instance = new HibernateUtil();
}
return instance;
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void beginTransaction() {
hibernateSession.beginTransaction();
}
public static void commitTransaction() {
hibernateSession.getTransaction().commit();
}
public static void rollbackTransaction() {
hibernateSession.getTransaction().rollback();
}
public static void closeSession() {
hibernateSession = (Session) session.get();
if(hibernateSession.isOpen()) {
hibernateSession.close();
}
session.set(hibernateSession);
}
public static Session getSession() {
hibernateSession = (Session) session.get();
try
{
if (hibernateSession == null || !hibernateSession.isOpen()) {
hibernateSession = getSessionFactory().openSession();
}
} catch (Exception e) {
System.out.println(e);
throw new RuntimeException(e);
}
session.set(hibernateSession);
return hibernateSession;
}
}