Spring Hibernate: no se pudo obtener la sesión sincronizada con la transacción para el hilo actual

106

Creé una aplicación con spring + hibernate, pero siempre obtengo este error. Esta es mi primera aplicación con hibernación, leí algunas guías pero no puedo resolver este problema. ¿Dónde estoy haciendo mal?

Este es el código de mi aplicación.

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)

estudiante.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

estudianteDAO.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
fuente
3
¿Intentó agregar un @Transactional a su método de creación de DAO?
Juan
1
Olvidó declarar un HibernateTransactionManager y hacer que el método usando Hibernate sea transaccional.
JB Nizet
@itachi no es correcto, sessionFactory.openSession()la transacción se desactivará. Porque no son la misma sesión. > ¡Agregue la anotación @Transactional of spring en la clase service @Patrikoko es correcta! vea esta pregunta: stackoverflow.com/questions/15620355/… ejemplo:@Transactional(readOnly = true, propagation = Propagation.REQUIRED, rollbackFor = {java.lang.Exception.class})
nvnpnco

Respuestas:

200

Debe permitir que el soporte de transacciones ( <tx:annotation-driven>o @EnableTransactionManagement) y declarar el transactionManagery debería funcionar a través de la SessionFactory.

Debes agregar @Transactionala tu@Repository

With @Transactionalin your @RepositorySpring puede aplicar soporte transaccional en su repositorio.

Su Studentclase no tiene las anotaciones @ javax.persistence. * Cómo @Entity, supongo que la configuración de mapeo para esa clase se ha definido a través de XML.

Manuel Jordán
fuente
1
Por favor, ¿pueden escribir el código de la aplicación porque no funciona? Esta es mi primera aplicación con Hibernate
Alex
3
El equivalente de anotación de <tx: annotation-drive> es @EnableTransactionManagement
Anand Rockzz
5
Además, asegúrese de usar org.springframework.transaction.annotation.Transactional, no javax.persistance.Transactional
imnd_neel
Saludos amigo, no puedo creer que me perdí esta anotación :).
Boldbayar
1
Intenté durante horas que la transacción funcionara y finalmente usé @EnableTransactionManagement en lugar de <tx: annotation-drive> y todo funciona perfectamente. No puedo agradecerles lo suficiente Manuel
Abu Sulaiman
38

Tuve el mismo problema, pero en una clase que no formaba parte de la capa de servicio. En mi caso, el administrador de transacciones simplemente se obtuvo del contexto mediante el getBean()método, y la clase pertenecía a la capa de vista; mi proyecto utiliza la OpenSessionInViewtécnica.

El sessionFactory.getCurrentSession()método ha estado provocando la misma excepción que la del autor. La solución para mí fue bastante simple.

Session session;

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

Si el getCurrentSession()método falla, openSession()debería funcionar.

itachi
fuente
al actualizar de Hibernate3 a Hibernate5, tuve que cambiar el código de SessionFactoryUtils.getSession () a sessionFactory.getCurrentSession (). Encontré el mismo error en ese momento.
user811433
2
Esto da el comportamiento realmente desagradable de que si sessionFactory.getCurrentSession();tiene éxito, la sesión no debe cerrarse, pero si sessionFactory.openSession();tiene éxito, debe cerrarse
Richard Tingle
1
De acuerdo @RichardTingle. Parece que openSession es un truco para evitar la excepción. ¿Cuál debería ser la solución inactiva para esto?
Praveen Shendge
@Praveen, lo que realmente hice fue que un servicio aceptara una lambda que Function<Session,T>significa "si tuviera una sesión, la usaría para hacer X". Luego, el método maneja el aprovisionamiento y (si es necesario) el desaprovisionamiento de la sesión, y solo devuelve la T.Por lo tanto, los consumidores externos del servicio nunca tienen en sus manos una sesión
Richard Tingle
Esto hizo que mi programa se ejecutara sin signos de error. Me preocupa no tener una transacción en varias consultas creadas de esta manera, lo que significa que corro el riesgo de devolver resultados inconsistentes.
Ole VV
13

Agregue la anotación @Transactional of spring en el servicio de clase

Patrikoko
fuente
3

En su xyz.DAOImpl.java

Realice los siguientes pasos:

// Paso 1: Establecer fábrica de sesiones

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

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

// Paso 2: Intente obtener la sesión actual y detecte la excepción HibernateException.


// Paso 3: Si hay alguna excepción de HibernateException, entonces es verdadero para obtener openSession.

try 
{
    //Step-2: Implementation
    session = sessionFactory.getCurrentSession();
} 
catch (HibernateException e) 
{
    //Step-3: Implementation
    session = sessionFactory.openSession();
}
ArunDhwaj IIITH
fuente
¡Hola! ¿No se supone que Hibernate debe hacer eso por sí mismo?
Chris
2

¡Agregué esta configuración en web.xml y funciona bien para mí!

<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>

Además, la respuesta más clasificada me da pistas para evitar que la aplicación entre en pánico en la primera ejecución.

何德福
fuente
1
Estoy usando springMVC 4 e Hibernate 5
何德福
2

Debe permitir la transacción a su método DAO. Añadir,

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

sobre tus métodos dao. Y @Transactionaldebe ser del paquete:

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

También tuve este error porque en el archivo donde usé la @Transactional anotación, estaba importando la clase incorrecta

import javax.transaction.Transactional; 

En lugar de javax, use

import org.springframework.transaction.annotation.Transactional; 
marron
fuente
1

Mi solución fue (usando Spring) poner el método que falla dentro de otro método que crea y confirma la transacción.

Para hacer eso, primero inyecté lo siguiente:

@Autowired
private PlatformTransactionManager transactionManager;

Y finalmente hizo esto:

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

    oldMethod();

    transactionManager.commit(transaction);
}
Aliuk
fuente
1

@Transactional =javax.transaction.Transactional. Ponlo justo al lado @Repository.

Alter Hu
fuente
0

Mi configuración era así. Tenía un QuartzJob , un Service Bean y un Dao. como de costumbre, se configuró con LocalSessionFactoryBean (para hibernación) y SchedulerFactoryBean para el marco Quartz. mientras escribía el trabajo de Quartz, por error lo anoté con @ Service , no debería haberlo hecho porque estaba usando otra estrategia para conectar el QuartzBean usando AutowiringSpringBeanJobFactory extendiendo SpringBeanJobFactory .

Entonces, lo que en realidad estaba sucediendo es que debido a Quartz Autowire, TX se estaba inyectando en Job Bean y, al mismo tiempo, el contexto de Tx se estableció en virtud de @ Service anotación y, por lo tanto, ¡el TX se estaba desincronizando!

Espero que ayude a aquellos para quienes las soluciones anteriores realmente no resolvieron el problema. Estaba usando Spring 4.2.5 e Hibernate 4.0.1,

Veo que en este hilo hay una sugerencia innecesaria para agregar la anotación @ Transactional al DAO (@ Repository ), esa es una sugerencia inútil porque @ Repository tiene todo lo que necesita, no tiene que configurar especialmente ese @ transaccional en DAO, como se llama a los DAO desde los servicios que ya han sido inyectados por @Trasancational . Espero que esto pueda ser útil para las personas que usan Quartz, Spring e Hibernate juntos.

SANJAY GAUTAM
fuente
0

Agregue transaction-managera su <annotation-driven/>en spring-servlet.xml:

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

Revisa tu clase de dao. Debe ser así:

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

Y anotaciones:

@Transactional
@Repository
Evgeniya O
fuente
0

Encontré el mismo problema y finalmente descubrí que <tx:annotaion-driven />no estaba definido dentro de la clase anotada [dispatcher]-servlet.xmldonde el elemento de exploración de componentes habilitó @service.

En pocas palabras, <tx:annotaion-driven />con el elemento de escaneo de componentes juntos, el problema desapareció.

Sotavento
fuente
0

Mi problema similar se solucionó con los siguientes 2 enfoques.

1) Mediante el manejo manual de transacciones:

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

2) Dígale a Spring que abra y administre transacciones por usted en sus web.xmlfiltros y asegúrese 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
fuente
0

Gracias por el comentario de mannedear. Yo uso springmvc y en mi caso tengo que usarlo como

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

y también agrego spring-context a pom.xml y funciona

Justicia
fuente
0

Tuve el mismo problema. Lo resolví haciendo lo siguiente:

  1. Agregue esta línea al dispatcher-servletarchivo:

    <tx:annotation-driven/>

    Consulte la <beans>sección anterior en el mismo archivo. Estas dos líneas deben 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. También asegúrese de haber agregado @Repositoryy de @Transactionaldónde está usando sessionFactory.

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

En esta clase anterior, @Repositorysolo coloqué una anotación más @Transactional, funcionará. Si funciona, responde ( Y/ N):

@Repository
@Transactional
public class StudentDAOImpl implements StudentDAO
Sunil Jaiswal
fuente
1
Bienvenido a SO. Sírvase leer cómo escribo una buena respuesta . En SO no existe la costumbre de responder S / N. Si su respuesta funciona para la persona, marcarán como aceptada. También se podría votar a favor una respuesta útil.
Sri9911