Spring Hibernate - Impossible d'obtenir une session synchronisée par transaction pour le thread actuel


106

J'ai créé une application avec spring + hibernate, mais j'obtiens toujours cette erreur. C'est ma première application avec hibernate, j'ai lu quelques guides mais je n'arrive pas à résoudre ce problème. Où vais-je mal?

Ceci est le code de mon application

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

étudiantDAO.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)
);

3
Avez-vous essayé d'ajouter un @Transactional à votre méthode de création DAO?
John

1
Vous avez oublié de déclarer un HibernateTransactionManager et de rendre la méthode utilisant Hibernate transactionnelle.
JB Nizet

@itachi n'est pas correct, sessionFactory.openSession()la transaction sera désactivée. Parce qu'ils ne sont pas la même session. > Ajouter l'annotation @Transactional of spring dans la classe service @Patrikoko c'est correct! voir cette question: stackoverflow.com/questions/15620355/… exemple:@Transactional(readOnly = true, propagation = Propagation.REQUIRED, rollbackFor = {java.lang.Exception.class})
nvnpnco

Réponses:


200

Vous devez activer la prise en charge des transactions ( <tx:annotation-driven>ou @EnableTransactionManagement) et déclarer le transactionManageret il devrait fonctionner via le SessionFactory.

Vous devez ajouter @Transactionalà votre@Repository

With @Transactionalin your @RepositorySpring est capable d'appliquer le support transactionnel dans votre référentiel.

Votre Studentclasse n'a pas d'annotations @ javax.persistence. * Comment @Entity, je suppose que la configuration de mappage pour cette classe a été définie via XML.


1
S'il vous plaît, pouvez-vous écrire le code de l'application car cela ne fonctionne pas ... Ceci est ma première application avec Hibernate
Alex

3
L'équivalent d'annotation de <tx: annotation-driven> est @EnableTransactionManagement
Anand Rockzz

5
Assurez-vous également d'utiliser org.springframework.transaction.annotation.Transactional, et non javax.persistance.Transactional
imnd_neel

Salut mon pote, je ne peux pas croire que j'ai raté cette annotation :).
Boldbayar

1
J'ai essayé pendant des heures de faire fonctionner la transaction et finalement j'ai utilisé @EnableTransactionManagement au lieu de <tx: annotation-driven> et tout fonctionne parfaitement. Je ne saurais trop vous remercier Manuel
Abu Sulaiman

38

J'ai eu le même problème, mais dans une classe qui ne faisait pas partie de la couche de service. Dans mon cas, le gestionnaire de transactions a simplement été obtenu à partir du contexte par la getBean()méthode, et la classe appartenait à la couche de vue - mon projet utilise la OpenSessionInViewtechnique.

La sessionFactory.getCurrentSession()méthode a causé la même exception que celle de l'auteur. La solution pour moi était plutôt simple.

Session session;

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

Si la getCurrentSession()méthode échoue, le openSession()devrait faire l'affaire.


lors de la mise à niveau de Hibernate3 vers Hibernate5, j'ai dû changer le code de SessionFactoryUtils.getSession () en sessionFactory.getCurrentSession (). Je suis tombé sur la même erreur à ce moment-là.
user811433

2
Cela donne le comportement vraiment désagréable que si sessionFactory.getCurrentSession();réussit, la session ne doit pas être fermée mais si sessionFactory.openSession();elle réussit, elle doit être fermée
Richard Tingle

1
D'accord @RichardTingle. On dirait qu'openSession est un hack pour contourner l'exception. Quelle devrait être la solution inactive pour cela?
Praveen Shendge

@Praveen ce que j'ai fait en fait était d'avoir un service acceptant un lambda Function<Session,T>signifiant "si j'avais une session, je l'utiliserais pour faire X". Ensuite, la méthode gère l'approvisionnement et (si nécessaire) la suppression du provisionnement de la session, et renvoie simplement le T.Ainsi, les consommateurs externes du service ne mettent jamais la main sur une session
Richard Tingle

Cela a fait fonctionner mon programme sans signe d'erreur. Je crains de ne pas avoir de transaction sur plusieurs requêtes créées de cette manière, ce qui signifie que je risque de renvoyer des résultats incohérents?
Ole VV le

13

Ajouter l'annotation @Transactional of spring dans le service de classe


3

Dans votre xyz.DAOImpl.java

Suivez les étapes suivantes:

// Étape 1: définir la fabrique de session

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

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

// Étape 2: essayez d'obtenir la session en cours et interceptez l'exception HibernateException.


// Étape 3: S'il y a une exception HibernateException, alors true pour obtenir openSession.

try 
{
    //Step-2: Implementation
    session = sessionFactory.getCurrentSession();
} 
catch (HibernateException e) 
{
    //Step-3: Implementation
    session = sessionFactory.openSession();
}

Salut! Hibernate n'est-il pas censé le faire tout seul?
Chris

2

J'ai ajouté ces configurations dans web.xml et cela fonctionne bien pour moi!

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

De plus, la réponse la plus classée me donne des indices pour empêcher l'application de paniquer lors de la première exécution.


1
J'utilise springMVC 4 et Hibernate 5
何德福

2

Vous devez autoriser la transaction à votre méthode DAO. Ajouter,

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

sur vos méthodes dao. Et @Transactionaldevrait être du paquet:

org.springframework.transaction.annotation.Transactional

1

J'ai eu cette erreur aussi parce que dans le fichier où j'ai utilisé l' @Transactional annotation, j'importais la mauvaise classe

import javax.transaction.Transactional; 

Au lieu de javax, utilisez

import org.springframework.transaction.annotation.Transactional; 

1

Ma solution consistait (en utilisant Spring) à mettre la méthode qui échoue dans une autre méthode qui crée et valide la transaction.

Pour ce faire, j'ai d'abord injecté ce qui suit:

@Autowired
private PlatformTransactionManager transactionManager;

Et finalement fait ceci:

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

    oldMethod();

    transactionManager.commit(transaction);
}

1

@Transactional =javax.transaction.Transactional. Mettez-le juste à côté @Repository.


0

Ma configuration était comme ça. J'avais un QuartzJob , un Service Bean et Dao. comme d'habitude, il a été configuré avec LocalSessionFactoryBean (pour la mise en veille prolongée) et SchedulerFactoryBean pour le framework Quartz. lors de l'écriture du travail Quartz, je l'ai par erreur annoté avec @ Service , je n'aurais pas dû le faire car j'utilisais une autre stratégie pour câbler le QuartzBean en utilisant AutowiringSpringBeanJobFactory étendant SpringBeanJobFactory .

Donc, ce qui se passait réellement, c'est qu'en raison de Quartz Autowire, TX était injecté dans le Job Bean et en même temps, le contexte Tx était défini en vertu de @ Service annotation et donc le TX tombait hors de synchronisation !!

J'espère que cela aidera ceux pour qui les solutions ci-dessus n'ont vraiment pas résolu le problème. J'utilisais Spring 4.2.5 et Hibernate 4.0.1,

Je vois que dans ce fil, il y a une suggestion inutile d'ajouter une annotation @ Transactional au DAO (@ Repository ), c'est une suggestion inutile car @ Repository a tout ce dont il a besoin pour ne pas avoir à définir spécialement ce @ transactionnel sur DAO, comme les DAO sont appelés à partir des services qui ont déjà été injectés par @Trasancational . J'espère que cela pourrait être utile aux personnes qui utilisent ensemble Quartz, Spring et Hibernate.


0

Ajouter transaction-managerà votre <annotation-driven/>au printemps servlet.xml:

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

0

Vérifiez votre classe de dao. Ça doit être comme ça:

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

Et annotations:

@Transactional
@Repository

0

J'ai rencontré le même problème et j'ai finalement découvert que le <tx:annotaion-driven />n'était pas défini dans la classe annotée [dispatcher]-servlet.xmlwhere component-scan element enabled @service.

Simplement mis ensemble <tx:annotaion-driven />avec l'élément d'analyse de composant, le problème a disparu.


0

Mon problème similaire a été résolu avec les 2 approches ci-dessous.

1) Grâce à la gestion manuelle des transactions:

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

2) Dites à Spring d'ouvrir et de gérer les transactions pour vous dans vos web.xmlfiltres et assurez-vous d'utiliser @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>

0

Merci pour le commentaire de mannedear. J'utilise springmvc et dans mon cas je dois utiliser comme

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

et j'ajoute également spring-context à pom.xml et cela fonctionne


0

J'ai eu le même problème. Je l'ai résolu en procédant comme suit:

  1. Ajoutez la ligne this au dispatcher-servletfichier:

    <tx:annotation-driven/>

    Vérifiez la <beans>section ci - dessus dans le même fichier. Ces deux lignes doivent être présentes:

    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. Assurez-vous également que vous avez ajouté @Repositoryet @Transactionaloù vous utilisez sessionFactory.

    @Repository
    @Transactional
    public class ItemDaoImpl implements ItemDao {
        @Autowired
        private SessionFactory sessionFactory;

-1

Dans cette classe ci @Repository- dessus vient de placer une autre annotation, @Transactionalcela fonctionnera. Si cela fonctionne, répondez ( Y/ N):

@Repository
@Transactional
public class StudentDAOImpl implements StudentDAO

1
Bienvenue à SO. Veuillez passer par Comment écrire une bonne réponse . Dans SO, il n'y a pas de coutume de répondre O / N. Si votre réponse fonctionne pour la personne qu'elle marquera, elle est acceptée. Une réponse utile pourrait également être votée pour.
Sri9911
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.