Spring Hibernate - 无法为当前线程获取事务同步会话
Posted
技术标签:
【中文标题】Spring Hibernate - 无法为当前线程获取事务同步会话【英文标题】:Spring Hibernate - Could not obtain transaction-synchronized Session for current thread 【发布时间】:2014-11-29 22:59:42 【问题描述】:我用 spring + hibernate 创建了一个应用程序,但我总是得到这个错误。这是我第一个使用休眠的应用程序,我阅读了一些指南,但我无法解决这个问题。我哪里做错了?
这是我的应用程序代码
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
学生DAOImpl.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)
);
【问题讨论】:
您是否尝试将@Transactional 添加到您的DAO 创建方法中? 您忘记声明 HibernateTransactionManager,并让使用 Hibernate 事务的方法。 @itachi 不正确,sessionFactory.openSession()
事务将被禁用。因为它们不是同一个会话。 > 在类服务@Patrikoko 中添加spring 的注解@Transactional 是正确的!看到这个问题:***.com/questions/15620355/… 例如:@Transactional(readOnly = true, propagation = Propagation.REQUIRED, rollbackFor = java.lang.Exception.class)
【参考方案1】:
您必须启用事务支持(<tx:annotation-driven>
或 @EnableTransactionManagement
)并声明transactionManager
,它应该可以通过SessionFactory
工作。
您必须将@Transactional
添加到您的@Repository
在您的@Repository
中使用@Transactional
,Spring 能够将事务支持应用到您的存储库中。
您的Student
类没有@javax.persistence.*
注释,如何@Entity
,我假设该类的映射配置已通过 XML 定义。
【讨论】:
拜托,你能写应用程序的代码吗,因为它不起作用..这是我第一个使用 Hibernate 的应用程序 注解等价于 是 @EnableTransactionManagement 另外,请确保使用 org.springframework.transaction.annotation.Transactional,而不是 javax.persistance.Transactional 我已经尝试了几个小时来让事务正常工作,最后我使用 @EnableTransactionManagement 而不是 并且一切正常。我非常感谢你,曼努埃尔 在我的 DAO 类中添加了@EnableTransactionManagement
和 @Transactional
后,这非常有效。【参考方案2】:
我也遇到过同样的问题,但是在一个不属于服务层的类中。在我的例子中,事务管理器只是通过getBean()
方法从上下文中获取的,并且该类属于视图层——我的项目使用了OpenSessionInView
技术。
sessionFactory.getCurrentSession()
方法一直导致与作者相同的异常。对我来说解决方案相当简单。
Session session;
try
session = sessionFactory.getCurrentSession();
catch (HibernateException e)
session = sessionFactory.openSession();
如果 getCurrentSession()
方法失败,openSession()
应该可以解决问题。
【讨论】:
从 Hibernate3 升级到 Hibernate5 时,我不得不将代码从 SessionFactoryUtils.getSession() 更改为 sessionFactory.getCurrentSession()。当时遇到了同样的错误。 这给出了真正令人讨厌的行为,如果sessionFactory.getCurrentSession();
成功,则不应关闭会话,但如果sessionFactory.openSession();
成功,则必须关闭它
同意@RichardTingle。似乎 openSession 是绕过异常的黑客。什么应该是空闲的解决方案?
@Praveen 我实际上所做的是让服务接受一个 lambda Function<Session,T>
,意思是“如果我有一个会话,我会用它来做 X”。然后该方法处理配置和(如果需要)取消配置会话,并仅返回 T。因此服务的外部消费者永远不会真正接触到会话
这使我的程序运行没有错误迹象。我担心我没有以这种方式创建的多个查询之间的事务,这意味着我可能会返回不一致的结果?【参考方案3】:
在类服务中添加spring的@Transactional注解
【讨论】:
【参考方案4】:在你的 xyz.DAOImpl.java 中
执行以下步骤:
//Step-1:设置会话工厂
@Resource(name="sessionFactory")
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf)
this.sessionFactory = sf;
//Step-2:尝试获取当前会话,并捕获HibernateException异常。
//Step-3:如果有任何HibernateException异常,则true获取openSession。
try
//Step-2: Implementation
session = sessionFactory.getCurrentSession();
catch (HibernateException e)
//Step-3: Implementation
session = sessionFactory.openSession();
【讨论】:
嗨! Hibernate 不应该自己做吗?【参考方案5】:您需要允许对您的 DAO 方法进行事务处理。 添加,
@Transactional(readOnly = true, propagation=Propagation.NOT_SUPPORTED)
在你的 dao 方法上。
而@Transactional
应该来自包:
org.springframework.transaction.annotation.Transactional
【讨论】:
【参考方案6】:我在 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>
此外,排名最高的答案为我提供了防止应用程序在第一次运行时出现恐慌的线索。
【讨论】:
我正在使用 springMVC 4 和 Hibernate 5【参考方案7】:我也遇到了这个错误,因为在我使用 @Transactional
注释的文件中,我导入了错误的类
import javax.transaction.Transactional;
用 javax 代替
import org.springframework.transaction.annotation.Transactional;
【讨论】:
【参考方案8】:我的解决方案是(使用 Spring)将失败的方法放在另一个创建并提交事务的方法中。
为此,我首先注入了以下内容:
@Autowired
private PlatformTransactionManager transactionManager;
终于做到了:
public void newMethod()
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus transaction = transactionManager.getTransaction(definition);
oldMethod();
transactionManager.commit(transaction);
【讨论】:
【参考方案9】:@Transactional =javax.transaction.Transactional
。放在@Repository
旁边。
【讨论】:
【参考方案10】:我的配置是这样的。我有一个 QuartzJob 、一个 Service Bean 和 Dao 。像往常一样,它配置了 LocalSessionFactoryBean(用于休眠)和用于 Quartz 框架的 SchedulerFactoryBean。在编写 Quartz 作业时,我错误地用 @Service 对其进行了注释,我不应该这样做,因为我正在使用另一种策略来使用 AutowiringSpringBeanJobFactory 连接 QuartzBean 扩展 SpringBeanJobFactory。
所以实际发生的情况是,由于 Quartz Autowire ,TX 被注入到 Job Bean 中,同时 Tx 上下文是通过 @Service 注释设置的,因此 TX 是不同步!!
我希望它对那些上面的解决方案确实没有解决问题的人有所帮助。我使用的是 Spring 4.2.5 和 Hibernate 4.0.1 ,
我看到在这个线程中有一个不必要的建议将 @Transactional 注释添加到 DAO(@Repository) ,这是一个无用的建议,因为 @Repository 拥有它需要的所有东西,不必在 DAO 上专门设置 @transactional,因为 DAO 是从 已经注入的服务中调用的@Trasancational 。我希望这可能对一起使用 Quartz 、 Spring 和 Hibernate 的人有所帮助。
【讨论】:
【参考方案11】:在 spring-servlet.xml:
中将transaction-manager
添加到您的<annotation-driven/>
<tx:annotation-driven transaction-manager="yourTransactionBeanID"/>
【讨论】:
【参考方案12】:检查你的 dao 类。应该是这样的:
Session session = getCurrentSession();
Query query = session.createQuery(GET_ALL);
和注释:
@Transactional
@Repository
【讨论】:
【参考方案13】:我遇到了同样的问题,最后发现<tx:annotaion-driven />
没有在[dispatcher]-servlet.xml
中定义,其中组件扫描元素启用了@service
注释类。
只需将<tx:annotaion-driven />
与组件扫描元素放在一起,问题就消失了。
【讨论】:
【参考方案14】:我的类似问题通过以下 2 种方法得到解决。
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>
【讨论】:
【参考方案15】:在@Repository
上面的这个类中,只需再添加一个注解@Transactional
就可以了。如果有效,回复(Y
/N
):
@Repository
@Transactional
public class StudentDAOImpl implements StudentDAO
【讨论】:
欢迎来到 SO。请通过How do I write a good answer。在 SO 中没有回复 Y/N 的习惯。如果您的答案适用于他们将标记为已接受的人。一个有用的答案也可能会被投票。【参考方案16】:感谢 mannedear 的评论。我使用 springmvc,在我的情况下我必须使用 as
@Repository
@Transactional
@EnableTransactionManagement
public class UserDao
...
我还将 spring-context 添加到 pom.xml 并且它可以工作
【讨论】:
【参考方案17】:我有同样的问题。我通过以下方式解决了它:
将此行添加到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"
还要确保在使用 sessionFactory
的位置添加了 @Repository
和 @Transactional
。
@Repository @Transactional public class ItemDaoImpl implements ItemDao @Autowired private SessionFactory sessionFactory;
【讨论】:
【参考方案18】:我的数据库表的列名与 Java 对象 (@Entity) 不匹配,导致引发上述异常。
通过使用适当的列名更新表可以解决此问题。
【讨论】:
【参考方案19】:在我的情况下,问题是控制器尝试使用 @Repository 直接访问 DAO。 在@Repository 之上添加@Service 层解决了这个问题
【讨论】:
以上是关于Spring Hibernate - 无法为当前线程获取事务同步会话的主要内容,如果未能解决你的问题,请参考以下文章
Spring + Hibernate:没有为当前线程找到会话
无法使用 Hibernate 在 Spring Boot 中将 MongoDB 设置为自动递增