Spring Hibernate - Impossibile ottenere la sessione sincronizzata con la transazione per il thread corrente


106

Ho creato un'applicazione con spring + hibernate, ma ottengo sempre questo errore. Questa è la mia prima applicazione con ibernazione, ho letto alcune guide ma non riesco a risolvere questo problema. Dove sto sbagliando?

Questo è il codice della mia applicazione

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

3
Hai provato ad aggiungere un @Transactional al tuo metodo di creazione DAO?
Giovanni

1
Hai dimenticato di dichiarare un HibernateTransactionManager e di rendere transazionale il metodo utilizzando Hibernate.
JB Nizet

@itachi non è corretto, sessionFactory.openSession()la transazione verrà disabilitata. Perché non sono la stessa sessione. > Aggiungi l'annotazione @Transactional of spring nel servizio di classe @Patrikoko è corretto! vedi questa domanda: stackoverflow.com/questions/15620355/... esempio:@Transactional(readOnly = true, propagation = Propagation.REQUIRED, rollbackFor = {java.lang.Exception.class})
nvnpnco

Risposte:


200

È necessario abilitare il supporto della transazione ( <tx:annotation-driven>o @EnableTransactionManagement) e dichiarare il transactionManagere dovrebbe funzionare tramite SessionFactory.

Devi aggiungere @Transactionalal tuo@Repository

With @Transactionalin your @RepositorySpring è in grado di applicare il supporto transazionale al tuo repository.

La tua Studentclasse non ha le annotazioni @ javax.persistence. * Come @Entity, presumo che la configurazione della mappatura per quella classe sia stata definita tramite XML.


1
Per favore, puoi scrivere il codice dell'applicazione perché non funziona .. Questa è la mia prima applicazione con Hibernate
Alex

3
L'annotazione equivalente di <tx: annotation-driven> è @EnableTransactionManagement
Anand Rockzz

5
Inoltre, assicurati di utilizzare org.springframework.transaction.annotation.Transactional, non javax.persistance.Transactional
imnd_neel

Ciao amico, non posso credere di aver perso questa annotazione :).
Boldbayar

1
Ho provato per ore a far funzionare la transazione e alla fine ho usato @EnableTransactionManagement invece di <tx: annotation-driven> e tutto funziona perfettamente. Non posso ringraziarti abbastanza Manuel
Abu Sulaiman

38

Ho avuto lo stesso problema, ma in una classe che non faceva parte del livello di servizio. Nel mio caso, il gestore delle transazioni è stato semplicemente ottenuto dal contesto con il getBean()metodo e la classe apparteneva al livello di visualizzazione: il mio progetto utilizza la OpenSessionInViewtecnica.

Il sessionFactory.getCurrentSession()metodo ha causato la stessa eccezione dell'autore. La soluzione per me era piuttosto semplice.

Session session;

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

Se il getCurrentSession()metodo fallisce, openSession()dovrebbe fare il trucco.


durante l'aggiornamento da Hibernate3 a Hibernate5, ho dovuto modificare il codice da SessionFactoryUtils.getSession () a sessionFactory.getCurrentSession (). Mi sono imbattuto nello stesso errore in quel momento.
user811433

2
Questo dà il comportamento davvero sgradevole che se ha sessionFactory.getCurrentSession();successo, la sessione non dovrebbe essere chiusa ma se ha sessionFactory.openSession();successo deve essere chiusa
Richard Tingle

1
D'accordo @RichardTingle. Sembra che openSession sia un trucco per aggirare l'eccezione. Quale dovrebbe essere la soluzione inattiva per questo?
Praveen Shendge

@ Praveen quello che ho fatto in realtà è stato avere un servizio che accetta un lambda che Function<Session,T>significa "se avessi una sessione lo userei per fare X". Quindi il metodo gestisce il provisioning e (se necessario) il deprovisioning della sessione e restituisce solo la T. Quindi i consumatori esterni del servizio non
Richard Tingle

Questo ha fatto funzionare il mio programma senza alcun segno di errore. Sono preoccupato di non avere una transazione su più query create in questo modo, il che significa che rischio di restituire risultati incoerenti?
Ole VV

13

Aggiungi l'annotazione @Transactional di primavera nel servizio di classe


3

Nel tuo xyz.DAOImpl.java

Procedi nel seguente modo:

// Step-1: imposta la session factory

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

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

// Passaggio 2: provare a ottenere la sessione corrente e rilevare l'eccezione HibernateException.


// Passaggio 3: se sono presenti eccezioni HibernateException, true per ottenere openSession.

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

Ciao! Hibernate non dovrebbe farlo da solo?
Chris,

2

Ho aggiunto queste configurazioni in web.xml e funziona bene per me!

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

Inoltre, la risposta più classificata mi fornisce indizi per evitare che l'applicazione vada in panico alla prima esecuzione.


1
Sto usando springMVC 4 e Hibernate 5
何德福

2

Devi consentire la transazione al tuo metodo DAO. Inserisci,

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

sui tuoi metodi dao. E @Transactionaldovrebbe provenire dal pacchetto:

org.springframework.transaction.annotation.Transactional

1

Ho avuto anche questo errore perché nel file in cui ho usato l' @Transactional annotazione, stavo importando la classe sbagliata

import javax.transaction.Transactional; 

Invece di javax, usa

import org.springframework.transaction.annotation.Transactional; 

1

La mia soluzione è stata (usando Spring) inserire il metodo che fallisce all'interno di un altro metodo che crea e esegue il commit della transazione.

Per fare ciò ho prima iniettato quanto segue:

@Autowired
private PlatformTransactionManager transactionManager;

E alla fine ha fatto questo:

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

    oldMethod();

    transactionManager.commit(transaction);
}

1

@Transactional =javax.transaction.Transactional. Mettilo accanto @Repository.


0

La mia configurazione era così. Ho avuto un QuartzJob , un Service Bean e un Dao. come al solito è stato configurato con LocalSessionFactoryBean (per l'ibernazione) e SchedulerFactoryBean per il framework Quartz. mentre scrivevo il lavoro Quartz, per errore l'ho annotato con @ Service , non avrei dovuto farlo perché stavo usando un'altra strategia per cablare QuartzBean usando AutowiringSpringBeanJobFactory estendendo SpringBeanJobFactory .

Quindi quello che stava realmente accadendo è che a causa di Quartz Autowire, TX veniva iniettato nel Job Bean e allo stesso tempo Tx Context veniva impostato in virtù di @ Service e quindi il TX non era più sincronizzato !!

Spero che aiuti a coloro per i quali le soluzioni di cui sopra non hanno davvero risolto il problema. Stavo usando Spring 4.2.5 e Hibernate 4.0.1,

Vedo che in questo thread c'è un suggerimento non necessario per aggiungere l' annotazione @ Transactional al DAO (@ Repository ), questo è un suggerimento inutile perché @ Repository ha tutto ciò di cui ha bisogno non è necessario impostarlo appositamente @ transazionale su DAO, come vengono chiamati i DAO dai servizi che sono già stati iniettati da @Trasancational . Spero che questo possa essere utile alle persone che usano Quartz, Spring e Hibernate insieme.


0

Aggiungi transaction-manageral tuo <annotation-driven/>in spring-servlet.xml:

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

0

Controlla la tua lezione di dao. Deve essere così:

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

E annotazioni:

@Transactional
@Repository

0

Ho riscontrato lo stesso problema e alla fine ho scoperto che <tx:annotaion-driven />non era definito all'interno [dispatcher]-servlet.xmldell'elemento where component-scan abilitato@service classe annotata in cui l' .

Messo semplicemente <tx:annotaion-driven />con l'elemento component-scan insieme, il problema è scomparso.


0

Il mio problema simile è stato risolto con meno di 2 approcci.

1) Tramite la gestione manuale delle transazioni:

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

2) Dì a Spring di aprire e gestire le transazioni per te nei web.xmlfiltri e assicurati di utilizzare @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

Grazie per il commento di mannedear. Uso springmvc e nel mio caso devo usare as

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

e aggiungo anche spring-context a pom.xml e funziona


0

Ho avuto lo stesso problema. L'ho risolto facendo quanto segue:

  1. Aggiungi questa riga al dispatcher-servletfile:

    <tx:annotation-driven/>

    Controlla la <beans>sezione precedente nello stesso file. Queste due righe devono essere presenti:

    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. Assicurati anche di aver aggiunto @Repositorye @Transactionaldove stai usando sessionFactory.

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

-1

In questa classe sopra @Repositoryappena posizionata un'altra annotazione @Transactionalfunzionerà. Se funziona, rispondi ( Y/ N):

@Repository
@Transactional
public class StudentDAOImpl implements StudentDAO

1
Benvenuto in SO. Si prega di esaminare Come scrivo una buona risposta . In SO non c'è l'abitudine di rispondere S / N. Se la tua risposta funziona per la persona che contrassegneranno come accettata. Anche una risposta utile potrebbe essere votata.
Sri9911
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.