Spring Hibernate - Não foi possível obter a Sessão sincronizada com a transação para o thread atual

106

Criei um aplicativo com spring + hibernate, mas sempre recebo esse erro. Este é meu primeiro aplicativo com hibernação, li alguns guias mas não consigo resolver este problema. Onde estou fazendo errado?

Este é o código do meu aplicativo

ott 05, 2014 4:03:06 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
Informazioni: Refreshing   org.springframework.context.support.ClassPathXmlApplicationContext@1eab16b: startup date  [Sun Oct 05 16:03:06 CEST 2014]; root of context hierarchy
ott 05, 2014 4:03:06 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
Informazioni: Loading XML bean definitions from class path resource [springConfig.xml]
ott 05, 2014 4:03:08 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
ott 05, 2014 4:03:08 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core {4.3.6.Final}
ott 05, 2014 4:03:08 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
ott 05, 2014 4:03:08 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
ott 05, 2014 4:03:09 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
ott 05, 2014 4:03:09 PM org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
ott 05, 2014 4:03:09 PM org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory <init>
INFO: HHH000397: Using ASTQueryTranslatorFactory
Exception in thread "main" org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at coreservlets.StudentDAOImpl.create(StudentDAOImpl.java:19)
at coreservlets.MainApp.main(MainApp.java:14)

student.java

package coreservlets;

public class Student {

    private Integer id;
    private String name;
    private Integer age;

    public Integer getId(){return id;}//getId

    public void setId(Integer id){this.id=id;}//setId

    public String getName(){return name;}//getName

    public void setName(String name){this.name=name;}//setName

    public Integer getAge(){return age;}//getAge

    public void setAge(Integer age){this.age=age;}//setAge

}//Student

studentDAO.java

package coreservlets;

import org.hibernate.SessionFactory;

public interface StudentDAO {

    public void setSessionFactory(SessionFactory sessionFactory);

    public void create(String name,Integer age);

}//StudentDAO

StudentDAOImpl.java

package coreservlets;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class StudentDAOImpl implements StudentDAO {

    private SessionFactory sessionFactory;

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory){
        this.sessionFactory=sessionFactory;
    }//setSessionFactory

    public void create(String name,Integer age){
        Session session=sessionFactory.getCurrentSession();
        Student student=new Student();
        student.setName(name);
        student.setAge(age);
        session.save(student);
    }//create

}//StudentDAOImpl

MainApp.java

package coreservlets;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

    public static void main(String[] args) {

        ApplicationContext context=new ClassPathXmlApplicationContext("springConfig.xml");

        StudentDAOImpl student=(StudentDAOImpl) context.getBean("studentDAOImpl");

        student.create("Alessandro", new Integer(33));


    }//main

}//MainApp

springConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">

<context:annotation-config/>

<context:component-scan base-package="coreservlets"/>

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="jdbc:mysql://localhost:3306/spring_hibernate"/>
  <property name="username" value="root"/>
  <property name="password" value="password"/>
  <property name="initialSize" value="5"/>
  <property name="maxTotal" value="10"/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
    <value>
            hibernate.dialect=org.hibernate.dialect.MySQLDialect
    </value>
</property>

</bean>

</beans>

sql

create table student
(
id integer not null auto_increment,
name varchar(20) not null,
age integer not null,
primary key(id)
);
Alex
fonte
3
Você tentou adicionar um @Transactional ao seu método de criação DAO?
João
1
Você se esqueceu de declarar um HibernateTransactionManager e de tornar o método usando o Hibernate transacional.
JB Nizet
@itachi não está correto, sessionFactory.openSession()a transação será desativada. Porque eles não são a mesma sessão. > Adicione a anotação @Transactional of spring no serviço de classe @Patrikoko is correct! veja esta pergunta: stackoverflow.com/questions/15620355/… exemplo:@Transactional(readOnly = true, propagation = Propagation.REQUIRED, rollbackFor = {java.lang.Exception.class})
nvnpnco

Respostas:

200

Você deve ativar o suporte à transação ( <tx:annotation-driven>ou @EnableTransactionManagement) e declarar o transactionManagere ele deve funcionar por meio do SessionFactory.

Você deve adicionar @Transactionalem seu@Repository

Com @Transactionalem seu @RepositorySpring é capaz de aplicar suporte transacional em seu repositório.

Sua Studentclasse não tem as anotações @ javax.persistence. * Como @Entity, estou assumindo que a configuração de mapeamento para essa classe foi definida por meio de XML.

Manuel Jordan
fonte
1
Por favor, você pode escrever o código do aplicativo porque ele não funciona ... Este é meu primeiro aplicativo com Hibernate
Alex
3
O equivalente de anotação de <tx: annotation-driven> é @EnableTransactionManagement
Anand Rockzz
5
Além disso, certifique-se de usar org.springframework.transaction.annotation.Transactional, não javax.persistance.Transactional
imnd_neel
Saúde amigo, não acredito que perdi esta anotação :).
Boldbayar 01 de
1
Eu tentei por horas fazer a transação funcionar e finalmente usei @EnableTransactionManagement em vez de <tx: annotation-driven> e tudo funciona perfeitamente. Não posso agradecer o suficiente Manuel
Abu Sulaiman
38

Eu tive o mesmo problema, mas em uma classe que não fazia parte da camada de serviço. No meu caso, o gerenciador de transações foi simplesmente obtido do contexto pelo getBean()método, e a classe pertencia à camada de visualização - meu projeto utiliza OpenSessionInViewtécnica.

O sessionFactory.getCurrentSession()método, vem causando a mesma exceção do autor. A solução para mim foi bastante simples.

Session session;

try {
    session = sessionFactory.getCurrentSession();
} catch (HibernateException e) {
    session = sessionFactory.openSession();
}

Se o getCurrentSession()método falhar, o openSession()deve fazer o truque.

itachi
fonte
ao atualizar do Hibernate3 para o Hibernate5, tive que alterar o código de SessionFactoryUtils.getSession () para sessionFactory.getCurrentSession (). Encontrei o mesmo erro naquele momento.
user811433
2
Isso dá o comportamento realmente desagradável de que, se sessionFactory.getCurrentSession();for bem-sucedido, a sessão não deve ser encerrada, mas se sessionFactory.openSession();for bem-sucedida, deve ser encerrada
Richard Tingle
1
Concordo com @RichardTingle. Parece que o openSession é um hack para contornar a exceção. Qual deve ser a solução ociosa para isso?
Praveen Shendge
@Praveen, o que eu realmente fiz foi fazer com que um serviço aceitasse um lambda que Function<Session,T>significa "se eu tivesse uma sessão, usaria para fazer X". Em seguida, o método lida com o provisionamento e (se necessário) o desprovisionamento da sessão e apenas retorna o T. Assim, os consumidores externos do serviço nunca realmente colocam as mãos em uma sessão
Richard Tingle
Isso fez com que meu programa rodasse sem sinal de erro. Estou preocupado por não ter uma transação em várias consultas criadas dessa forma, o que significa que corro o risco de retornar resultados inconsistentes.
Ole VV
13

Adicione a anotação @Transactional of spring no serviço de classe

Patrikoko
fonte
3

Em seu xyz.DAOImpl.java

Execute as seguintes etapas:

// Etapa 1: Definir a fábrica da sessão

@Resource(name="sessionFactory")
private SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory sf)
{
    this.sessionFactory = sf;
}

// Etapa 2: Tentar obter a sessão atual e capturar a exceção HibernateException.


// Passo 3: Se houver alguma exceção HibernateException, true para obter openSession.

try 
{
    //Step-2: Implementation
    session = sessionFactory.getCurrentSession();
} 
catch (HibernateException e) 
{
    //Step-3: Implementation
    session = sessionFactory.openSession();
}
ArunDhwaj IIITH
fonte
Oi! O Hibernate não deveria fazer isso sozinho?
Chris
2

Eu adicionei essas configurações no web.xml e funciona bem para mim!

<filter>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
    <init-param>
        <param-name>sessionFactoryBeanName</param-name>
        <param-value>sessionFactory</param-value>
    </init-param>
    <init-param>
        <param-name>flushMode</param-name>
        <param-value>AUTO</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Além disso, a resposta mais classificada fornece pistas para evitar que o aplicativo entre em pânico na primeira execução.

何德福
fonte
1
Estou usando springMVC 4 e Hibernate 5
何德福
2

Você precisa permitir a transação para o seu método DAO. Adicionar,

@Transactional(readOnly = true, propagation=Propagation.NOT_SUPPORTED)

sobre seus métodos dao. E @Transactionaldeve ser da embalagem:

org.springframework.transaction.annotation.Transactional
RahuL Sharma
fonte
1

Também tive esse erro porque no arquivo onde usei a @Transactional anotação estava importando a classe errada

import javax.transaction.Transactional; 

Em vez de javax, use

import org.springframework.transaction.annotation.Transactional; 
sobrancelha
fonte
1

Minha solução foi (usando Spring) colocar o método que falha dentro de outro método que cria e confirma a transação.

Para fazer isso, primeiro injetei o seguinte:

@Autowired
private PlatformTransactionManager transactionManager;

E finalmente fiz isso:

public void newMethod() {
    DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
    TransactionStatus transaction = transactionManager.getTransaction(definition);

    oldMethod();

    transactionManager.commit(transaction);
}
Aliuk
fonte
1

@Transactional =javax.transaction.Transactional. Coloque ao lado @Repository.

Alter Hu
fonte
0

Minha configuração era assim. Eu tinha um QuartzJob , um Service Bean e um Dao. como de costume, ele foi configurado com LocalSessionFactoryBean (para hibernar) e SchedulerFactoryBean para o framework Quartz. enquanto escrevia o trabalho do Quartz, eu por engano anotei com @ Service , não deveria ter feito isso porque estava usando outra estratégia para conectar o QuartzBean usando AutowiringSpringBeanJobFactory estendendo SpringBeanJobFactory .

O que realmente estava acontecendo é que devido ao Quartz Autowire, o TX estava sendo injetado no Job Bean e ao mesmo tempo o Contexto Tx foi definido em virtude da anotação @ Serviço e, portanto, o TX estava saindo de sincronia !!

Espero que ajude aqueles para quem as soluções acima realmente não resolveram o problema. Eu estava usando Spring 4.2.5 e Hibernate 4.0.1,

Vejo que neste segmento há uma sugestão desnecessário acrescentar @ Transactional anotação para o DAO (@ Repository ), que é uma sugestão causa inútil @ Repository tem tudo o que ele precisa ter não tem que definir especialmente que @ transacional em DAOs, pois os DAOs são chamados a partir dos serviços que já foram injetados por @Trasancational . Espero que isso possa ajudar as pessoas que estão usando Quartz, Spring e Hibernate juntos.

SANJAY GAUTAM
fonte
0

Adicione transaction-managerao seu <annotation-driven/>in spring-servlet.xml:

<tx:annotation-driven transaction-manager="yourTransactionBeanID"/>
Majid
fonte
0

Verifique sua classe dao. Deve ser assim:

Session session = getCurrentSession();
Query query = session.createQuery(GET_ALL);

E anotações:

@Transactional
@Repository
Evgeniya O
fonte
0

Eu encontrei o mesmo problema e finalmente descobri que o <tx:annotaion-driven />não foi definido dentro da classe anotada [dispatcher]-servlet.xmlwhere component-scan enabled @service.

Basta juntar o <tx:annotaion-driven />elemento de varredura de componentes e o problema desapareceu.

Lee
fonte
0

Meu problema semelhante foi corrigido com 2 abordagens abaixo.

1) Por meio de transações de manipulação manual:

Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
UserInfo user = (UserInfo) session.get(UserInfo.class, 1);
tx.commit();

2) Diga ao Spring para abrir e gerenciar transações para você em seus web.xmlfiltros e certifique-se de usar @Repository @Transactional:

<filter>
  <filter-name>hibernateFilter</filter-name>
  <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
  <init-param>
    <param-name>sessionFactory</param-name>
    <param-value>session.factory</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>hibernateFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
Jajikanth Pydimarla
fonte
0

Obrigado pelo comentário de mannedear. Eu uso springmvc e no meu caso tenho que usar como

@Repository
@Transactional
@EnableTransactionManagement
public class UserDao {
...
}

e também adiciono spring-context a pom.xml e funciona

Lam
fonte
0

Eu tive o mesmo problema. Resolvi fazendo o seguinte:

  1. Adicione esta linha ao dispatcher-servletarquivo:

    <tx:annotation-driven/>

    Verifique a <beans>seção acima no mesmo arquivo. Essas duas linhas devem estar presentes:

    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation= "http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
  2. Além disso, certifique-se de adicionar @Repositorye @Transactionalonde está usando sessionFactory.

    @Repository
    @Transactional
    public class ItemDaoImpl implements ItemDao {
        @Autowired
        private SessionFactory sessionFactory;
Nimisha
fonte
-1

Nesta aula acima @Repositoryapenas coloquei mais uma anotação @Transactionalque vai funcionar. Se funcionar, responda de volta ( Y/ N):

@Repository
@Transactional
public class StudentDAOImpl implements StudentDAO
Sunil Jaiswal
fonte
1
Bem-vindo ao SO. Por favor, leia Como escrevo uma boa resposta . No SO, não há costume de responder S / N. Se a sua resposta funcionar para a pessoa que ela marcará, é aceita. Uma resposta útil também pode ser votada a favor.
Sri9911