Hibernacja wiosenna - nie można uzyskać sesji zsynchronizowanej z transakcją dla bieżącego wątku

106

Stworzyłem aplikację z spring + hibernate, ale zawsze otrzymuję ten błąd. To moja pierwsza aplikacja z hibernacją, przeczytałem kilka poradników, ale nie mogę rozwiązać tego problemu. Gdzie ja robię źle?

To jest kod mojej aplikacji

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
źródło
3
Czy próbowałeś dodać @Transactional do swojej metody tworzenia DAO?
Jan
1
Zapomniałeś zadeklarować HibernateTransactionManager i uczynić metodę wykorzystującą Hibernate transakcyjną.
JB Nizet
@itachi nie jest poprawne, sessionFactory.openSession()transakcja zostanie wyłączona. Ponieważ to nie ta sama sesja. > Dodaj adnotację @Transactional of spring w serwisie klasy @Patrikoko jest poprawne! zobacz to pytanie: stackoverflow.com/questions/15620355/ ... przykład:@Transactional(readOnly = true, propagation = Propagation.REQUIRED, rollbackFor = {java.lang.Exception.class})
nvnpnco

Odpowiedzi:

200

Musisz włączyć obsługę transakcji ( <tx:annotation-driven>lub @EnableTransactionManagement) i zadeklarowaćtransactionManager i powinno działać poprzez SessionFactory.

Musisz dodać @Transactionaldo swojego@Repository

With @Transactionalin your @RepositorySpring jest w stanie zastosować wsparcie transakcyjne do Twojego repozytorium.

Twoja Studentklasa nie ma adnotacji @ javax.persistence. *, Jak zakładam @Entity, że konfiguracja mapowania dla tej klasy została zdefiniowana za pomocą XML.

Manuel Jordan
źródło
1
Proszę, czy możesz napisać kod aplikacji, ponieważ nie działa. To moja pierwsza aplikacja z Hibernate
Alex
3
Odpowiednikiem adnotacji <tx: annotation-Based> jest @EnableTransactionManagement
Anand Rockzz
6
Upewnij się również, że używasz org.springframework.transaction.annotation.Transactional, a nie javax.persistance.Transactional
imnd_neel
Pozdrawiam, nie mogę uwierzyć, że przegapiłem tę adnotację :).
Boldbayar
1
Godzinami próbowałem, aby transakcja zadziałała i ostatecznie użyłem @EnableTransactionManagement zamiast <tx: annotation-Based> i wszystko działa idealnie. Nie mogę ci wystarczająco podziękować Manuel
Abu Sulaiman,
38

Miałem ten sam problem, ale w klasie, która nie była częścią warstwy usług. W moim przypadku menadżer transakcji został po prostu pozyskany z kontekstu getBean()metodą, a klasa należała do warstwy widoku - mój projekt wykorzystuje OpenSessionInViewtechnikę.

sessionFactory.getCurrentSession()Metoda została powodując ten sam wyjątek jako autora. Rozwiązanie dla mnie było raczej proste.

Session session;

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

Jeśli getCurrentSession()metoda zawiedzie, openSession()powinno załatwić sprawę.

itachi
źródło
podczas aktualizacji z Hibernate3 do Hibernate5 musiałem zmienić kod z SessionFactoryUtils.getSession () na sessionFactory.getCurrentSession (). W tym czasie napotkałem ten sam błąd.
user811433
2
Daje to naprawdę paskudne zachowanie, że jeśli się sessionFactory.getCurrentSession();powiedzie, sesja nie powinna zostać zamknięta, ale jeśli się sessionFactory.openSession();powiedzie, musi zostać zamknięta
Richard Tingle
1
Zgadzam się @RichardTingle. Wygląda na to, że openSession to sposób na obejście wyjątku. Jakie powinno być bezczynne rozwiązanie tego problemu?
Praveen Shendge,
@Praveen, co właściwie zrobiłem, to usługa akceptująca lambdę Function<Session,T>oznaczającą „gdybym miał sesję, użyłbym jej do zrobienia X”. Następnie metoda obsługuje obsługę administracyjną i (jeśli to konieczne) wyrejestrowywanie sesji, a po prostu zwraca T. Więc zewnętrzni konsumenci usługi nigdy nie dostają sesji
Richard Tingle
To spowodowało, że mój program działał bez śladu błędu. Martwię się, że nie mam transakcji obejmującej wiele zapytań utworzonych w ten sposób, co oznacza, że ​​ryzykuję zwrócenie niespójnych wyników?
Ole VV
13

Dodaj adnotację @Transactional of spring w usłudze klasowej

Patrikoko
źródło
3

W pliku xyz.DAOImpl.java

Wykonaj następujące kroki:

// Step-1: Ustaw fabrykę sesji

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

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

// Step-2: Spróbuj pobrać bieżącą sesję i złap wyjątek HibernateException.


// Step-3: Jeśli istnieje jakikolwiek wyjątek HibernateException, należy ustawić wartość true, aby uzyskać openSession.

try 
{
    //Step-2: Implementation
    session = sessionFactory.getCurrentSession();
} 
catch (HibernateException e) 
{
    //Step-3: Implementation
    session = sessionFactory.openSession();
}
ArunDhwaj IIITH
źródło
Cześć! Czy Hibernate nie powinien robić sam?
Chris
2

Dodałem tę konfigurację w web.xml i działa dobrze!

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

Dodatkowo, najbardziej sklasyfikowana odpowiedź daje mi wskazówki, jak zapobiec panice aplikacji przy pierwszym uruchomieniu.

何德福
źródło
1
Używam springMVC 4 i Hibernate 5
何德福
2

Musisz zezwolić na transakcje za pomocą metody DAO. Dodaj,

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

nad metodami dao. I @Transactionalpowinien być z paczki:

org.springframework.transaction.annotation.Transactional
RahuL Sharma
źródło
1

Miałem też ten błąd, ponieważ w pliku, w którym użyłem @Transactional adnotacji, importowałem niewłaściwą klasę

import javax.transaction.Transactional; 

Zamiast javax użyj

import org.springframework.transaction.annotation.Transactional; 
browndoor
źródło
1

Moim rozwiązaniem było (używając Springa) umieszczenie metody, która zawodzi, wewnątrz innej metody, która tworzy i zatwierdza transakcję.

Aby to zrobić, najpierw wstrzyknąłem:

@Autowired
private PlatformTransactionManager transactionManager;

I w końcu to zrobił:

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

    oldMethod();

    transactionManager.commit(transaction);
}
Aliuk
źródło
1

@Transactional =javax.transaction.Transactional. Połóż to tuż obok @Repository.

Alter Hu
źródło
0

Moja konfiguracja była taka. Miałem QuartzJob , Service Bean i Dao. jak zwykle został skonfigurowany z LocalSessionFactoryBean (dla hibernacji) i SchedulerFactoryBean dla frameworka Quartz. podczas pisania zadania Quartz przez pomyłkę oznaczyłem go adnotacją @ Service , nie powinienem był tego robić, ponieważ używałem innej strategii do okablowania QuartzBean przy użyciu AutowiringSpringBeanJobFactory rozszerzającego SpringBeanJobFactory .

Więc to, co faktycznie się działo, to to, że dzięki Quartz Autowire, TX był wstrzykiwany do Job Bean i jednocześnie Tx Context został ustawiony na mocy adnotacji @ Service, a zatem TX tracił synchronizację !!

Mam nadzieję, że pomoże to tym, dla których powyższe rozwiązania naprawdę nie rozwiązały problemu. Używałem Springa 4.2.5 i Hibernate 4.0.1,

Widzę, że w tym wątku jest niepotrzebna sugestia, aby dodać adnotację @ Transactional do DAO (@ Repository ), czyli bezużyteczną sugestię, ponieważ @ Repozytorium ma wszystko, czego potrzebuje, nie musi specjalnie ustawiać tego @ transakcyjnego na DAO, ponieważ DAO są wywoływane z usług, które zostały już wstrzyknięte przez @Trasancational . Mam nadzieję, że mogą to być pomocne osoby, które razem używają Quartz, Spring i Hibernate.

SANJAY GAUTAM
źródło
0

Dodaj transaction-managerdo swojej <annotation-driven/>w wiosenno-servlet.xml:

<tx:annotation-driven transaction-manager="yourTransactionBeanID"/>
Majid
źródło
0

Sprawdź swoją klasę dao. Musi wyglądać tak:

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

I adnotacje:

@Transactional
@Repository
Evgeniya O
źródło
0

Napotkałem ten sam problem i w końcu odkryłem, że element <tx:annotaion-driven />nie został zdefiniowany w klasie z adnotacjami, [dispatcher]-servlet.xmlgdzie element skanowania komponentu @servicewłączał.

Po prostu <tx:annotaion-driven />razem z elementem skanowania komponentowego problem zniknął.

Zawietrzny
źródło
0

Mój podobny problem został rozwiązany za pomocą poniższych 2 podejść.

1) Poprzez ręczną obsługę transakcji:

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

2) Powiedz Springowi, aby otwierał i zarządzał transakcjami w Twoich web.xmlfiltrach i upewnij się, że używasz @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
źródło
0

Dzięki za komentarz Mannedear. Używam springmvc iw moim przypadku muszę używać jako

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

dodam też kontekst wiosny do pom.xml i to działa

Chłostać
źródło
0

Miałem ten sam problem. Rozwiązałem to, wykonując następujące czynności:

  1. Dodaj ten wiersz do dispatcher-servletpliku:

    <tx:annotation-driven/>

    Sprawdź powyższą <beans>sekcję w tym samym pliku. Te dwie linie muszą być obecne:

    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. Upewnij się również, że dodałeś @Repositoryi @Transactionalgdzie używasz sessionFactory.

    @Repository
    @Transactional
    public class ItemDaoImpl implements ItemDao {
        @Autowired
        private SessionFactory sessionFactory;
Nimisha
źródło
-1

W tej klasie powyżej @Repositorywłaśnie umieściłem jeszcze jedną adnotację @Transactional, która zadziała. Jeśli to działa, odpowiedz ( Y/ N):

@Repository
@Transactional
public class StudentDAOImpl implements StudentDAO
sunil jaiswal
źródło
1
Witamy w SO. Uprzejmie przejdź przez Jak napisać dobrą odpowiedź . W SO nie ma zwyczaju odpowiadania T / N. Jeśli Twoja odpowiedź działa w przypadku osoby, którą oznaczy, jest zaakceptowana. Pomocna odpowiedź również może zostać przyjęta za.
Sri9911,