Spring Hibernate - не вдалось отримати синхронізовану транзакцію сесії для поточного потоку


106

Я створив програму Spring + в сплячку, але я завжди отримую цю помилку. Це моя перша заява на сплячку, я прочитав деякі посібники, але не можу вирішити цю проблему. Де я роблю неправильно?

Це код моєї заявки

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>

пл

create table student
(
id integer not null auto_increment,
name varchar(20) not null,
age integer not null,
primary key(id)
);

3
Ви намагалися додати метод @Transactional до методу створення DAO?
Іван

1
Ви забули оголосити HibernateTransactionManager і зробити метод, використовуючи Hibernate транзакцій.
JB Nizet

@itachi невірний, sessionFactory.openSession()транзакція буде відключена. Тому що вони не один і той же сеанс. > Додайте анотацію @Transactional весни в сервіс класів @Patrikoko правильно! побачити це питання: stackoverflow.com/questions/15620355 / ... приклад:@Transactional(readOnly = true, propagation = Propagation.REQUIRED, rollbackFor = {java.lang.Exception.class})
nvnpnco

Відповіді:


200

Ви повинні включити підтримку транзакцій ( <tx:annotation-driven>або @EnableTransactionManagement) і оголоситиtransactionManager і він повинен працювати через SessionFactory.

Ви повинні додати @Transactionalдо свого@Repository

З @Transactionalвашої @RepositorySpring ви зможете застосувати підтримку транзакцій у вашому сховищі.

Для вашого Studentкласу немає @ javax.persistence. * Примітки, як @Entity, я припускаю, що конфігурація Mapping для цього класу була визначена через XML


1
Будь ласка, чи можете ви написати код програми, тому що вона не працює. Це моя перша заявка на сплячку
Alex

3
Еквівалент анотації <tx: annotation-driven> - це @EnableTransactionManagement
Anand Rockzz

5
Також переконайтеся, що ви використовуєте org.springframework.transaction.annotation.Transactional, а не javax.persistance.Transactional
imnd_neel

Будьте здорові, я не можу повірити, що я пропустив цю анотацію :).
Болдбаяр

1
Я годинами намагався змусити транзакцію працювати, і нарешті я використав @EnableTransactionManagement замість <tx: annotation-driven>, і все працює чудово. Я не можу подякувати вам достатньо Мануеля
Абу-Сулеймана

38

У мене був той самий випуск, але в класі, який не входив до рівня обслуговування. У моєму випадку менеджер транзакцій був просто отриманий з контексту getBean()методом, а клас належав до шару перегляду - мій проект використовує OpenSessionInViewтехніку.

sessionFactory.getCurrentSession()Метод, завдавали таке ж виняток , як автор. Рішення для мене було досить простим.

Session session;

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

Якщо getCurrentSession()метод не вдається, openSession()слід зробити трюк.


при переході з Hibernate3 на Hibernate5 мені довелося змінити код з SessionFactoryUtils.getSession () на sessionFactory.getCurrentSession (). Натрапив на ту саму помилку в той час.
user811433

2
Це дає дійсно неприємну поведінку, що якщо sessionFactory.getCurrentSession();успіх, то сесія не повинна бути закритою, але якщо sessionFactory.openSession();вона успішна, вона повинна бути закритою
Річард Тінгл

1
Погодьтесь @RichardTingle. Здається, що openSession - це хак, щоб обійти виняток. Яким має бути рішення простою для цього?
Praveen Shendge

@Praveen те, що я насправді робив, - це послуга прийняти лямбда, що Function<Session,T>означає "якби я був сеанс, я би використовував це для X". Тоді метод обробляє резервування та (у разі потреби) видалення сеансу та просто повертає Т. Тож зовнішні споживачі послуги ніколи фактично не беруться на сеанс
Річард Тінгл

Це змусило мою програму працювати без ознак помилки. Я переживаю, що у мене немає транзакції за декілька створених таким чином запитів, це означає, що я ризикую повернути непослідовні результати?
Оле ВВ


3

У вашому xyz.DAOImpl.java

Виконайте наступні дії:

// Крок-1: Встановлення фабрики сеансу

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

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

// Крок-2: Спробуйте отримати поточний сеанс і перехопити виняток HibernateException.


// Крок-3: Якщо є якісь винятки HibernateException, тоді слід отримати trueSession.

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

Привіт! Хіба не повинен вважати, що сплячий робить це сам?
Кріс

2

Я додав ці налаштування в web.xml, і це добре працює для мене!

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

Крім того, найбільш рейтингова відповідь дає мені підказки, щоб запобігти застосуванню паніки під час першого запуску.


1
Я використовую springMVC 4 та Hibernate 5
何德福

2

Потрібно дозволити транзакцію до вашого методу DAO. Додати,

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

над вашими методами дао. І @Transactionalмає бути з пакета:

org.springframework.transaction.annotation.Transactional

1

У мене була і ця помилка, оскільки у файлі, де я використовував @Transactional анотацію, я імпортував неправильний клас

import javax.transaction.Transactional; 

Замість javax використовуйте

import org.springframework.transaction.annotation.Transactional; 

1

У моєму рішенні було (за допомогою Spring) введення методу, який провалюється всередині іншого методу, який створює та здійснює транзакцію.

Для цього я спочатку ввів наступне:

@Autowired
private PlatformTransactionManager transactionManager;

І нарешті зробив це:

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

    oldMethod();

    transactionManager.commit(transaction);
}


0

Моя конфігурація була такою. У мене були QuartzJob , Service Bean та Dao. як завжди, він налаштовувався за допомогою LocalSessionFactoryBean (для сплячого режиму) та SchedulerFactoryBean для Quartz. під час написання завдання з кварцу я помилково відзначив це за допомогою служби @ Service , я не повинен був цього робити, тому що використовував іншу стратегію, щоб передати QuartzBean за допомогою AutowiringSpringBeanJobFactory, що розширює SpringBeanJobFactory .

Отже, що насправді відбувалося, це те, що завдяки Quartz Autowire TX отримував ін'єкцію в Job Bean, і в той же час Tx Context був встановлений завдяки анотації @ Service і, отже, TX випадав із синхронізації !!

Я сподіваюся, що це допоможе тим, для кого вищезазначені рішення справді не вирішили питання. Я використовував Spring 4.2.5 та Hibernate 4.0.1,

Я бачу , що в цій темі є непотрібне пропозицію додати @ трансакціонної анотацію до DAO (@ Repository ), тобто марне пропозицію причини @ Repository є все , що йому потрібно , щоб не потрібно спеціально встановити , що @ трансакціонної на DAO, як називають DAO від служб, які вже вводили @Trasancational . Я сподіваюся, що це може бути корисним людям, які разом використовують кварц, весну та сплячку.


0

Додайте transaction-managerдо своїх <annotation-driven/>у Spring-servlet.xml:

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

0

Перевірте свій клас дао. Він повинен бути таким:

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

І примітки:

@Transactional
@Repository

0

Я зіткнувся з тією ж проблемою і, нарешті, з’ясував, що значення <tx:annotaion-driven />не було визначено в тому місці, [dispatcher]-servlet.xmlде елемент сканування компонентів включив @serviceанотований клас.

Простіше кажучи <tx:annotaion-driven />з елементами сканування компонентів разом, проблема зникла.


0

Мою аналогічну проблему виправили за допомогою нижче двох підходів.

1) Через операції вручну:

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

2) Скажіть Spring, щоб відкривати та керувати трансакціями для вас у ваших web.xmlфільтрах, і переконайтесь, що використовувати @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

Дякуємо за коментар mannedear. Я використовую springmvc, і в моєму випадку я повинен використовувати як

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

і я також додаю spring-context до pom.xml, і він працює


0

У мене було те саме питання. Я вирішив це, зробивши наступне:

  1. Додайте цей dispatcher-servletфайл у файл:

    <tx:annotation-driven/>

    Перевірте вищевказаний <beans>розділ у тому самому файлі. Ці два рядки повинні бути присутніми:

    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. Також переконайтеся, що ви додали @Repositoryта @Transactionalде використовуєте sessionFactory.

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

-1

У цьому класі вище @Repositoryрозміщено ще одну анотацію, @Transactionalвона працюватиме. Якщо це працює, відповісти назад ( Y/ N):

@Repository
@Transactional
public class StudentDAOImpl implements StudentDAO

1
Ласкаво просимо до SO. Будь ласка, перегляньте Як написати гарну відповідь . В ТА немає звичаю відповідати "Ні". Якщо ваша відповідь працює для людини, яку вона позначить, це прийнято. Корисна відповідь може бути також проголошена.
Sri9911
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.