我希望我的读取方法不使用事务,因为根本不需要它,我只用@Transactional标记我的创建/更新方法。但是我该怎么做?我有一个非常基本的Spring配置等...
SessionFactory 在我的DAO中注入,在每个方法中我调用sessionFactory。 getCurrentSession()。doQueryStuff();
然而,这会导致此错误:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
如果您需要我的Spring配置:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="be.howest.kidscalcula" />
<mvc:annotation-driven />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/kidscalcula" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
id="sessionFactory">
<property name="dataSource" ref="myDataSource" />
<property name="mappingResources">
<list>
<value>be/howest/kidscalcula/model/Foto.hbm.xml</value>
<value>be/howest/kidscalcula/model/Kindleerplanonderdeel.hbm.xml
</value>
<value>be/howest/kidscalcula/model/Klas.hbm.xml</value>
<value>be/howest/kidscalcula/model/Leerkracht.hbm.xml</value>
<value>be/howest/kidscalcula/model/Leerling.hbm.xml</value>
<value>be/howest/kidscalcula/model/Leerplan.hbm.xml</value>
<value>be/howest/kidscalcula/model/LeerplanOefenreeks.hbm.xml
</value>
<value>be/howest/kidscalcula/model/Leerplanonderdeel.hbm.xml</value>
<value>be/howest/kidscalcula/model/Niveau.hbm.xml</value>
<value>be/howest/kidscalcula/model/Oefenreeks.hbm.xml</value>
<value>be/howest/kidscalcula/model/Overgangsregel.hbm.xml</value>
<value>be/howest/kidscalcula/model/Rapport.hbm.xml</value>
<value>be/howest/kidscalcula/model/RapportLeerplanonderdeel.hbm.xml
</value>
<value>be/howest/kidscalcula/model/Schooljaar.hbm.xml</value>
<value>be/howest/kidscalcula/model/Subonderdeel.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.connection.pool_size">3</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
</props>
</property>
</bean>
<!-- Configure the multipart resolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="500000" />
</bean>
<!--
Transaction manager for a single Hibernate SessionFactory (alternative
to JTA)
-->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<tx:annotation-driven />
此错误是否与传播标准为必需的事实有关?
答案 0 :(得分:10)
将方法标记为事务性并且只读以确保事务不会修改任何数据:
@Transactional(readOnly=true)
使用Hibernate时,这是一个非常有用的优化。要详细了解此注释的含义,请阅读以下文章: Read-Only transactions with Spring and Hibernate
答案 1 :(得分:3)
正如消息中明确指出的那样,没有会话绑定到该线程,并且您指定的配置不允许创建“非事务”会话。我将尝试解释每个场景。
当你的配置中启用了Spring的事务时(正如你所做的那样),当调用SessionFactory.getCurrentSession时,Spring将使用代理来封装SessionFactory对象,该代理可以阻止创建新会话(如果尚未存在)。代理只会获取绑定到本地线程的当前会话,并且代码不允许创建临时会话(非事务性)。这就是您的配置阻止非交易会话创建的方式。
当您使用@Transactional注释方法/类时,Spring的TransactionInterceptor将创建一个会话,并在调用该方法时将其绑定到当前线程,以便以后可用。 Spring的OpenSessionInViewFilter,如果启用,还会将会话绑定到当前线程。由于您没有执行任何这些操作,因此未找到线程绑定会话。
您应该做的是使用@Transactional(readOnly = True)注释您的类,然后使用@Transactional(readOnly = False)注释您的创建/更新/删除方法。在读取数据时,必须具有只读事务。这可以确保没有人可以在该呼叫期间提交数据。
答案 2 :(得分:2)
即使使用Spring事务管理,也可以在事务之外启动会话。致电sessionFactory.openSession()
以获取新会话。此会话是本地会话,因为它不绑定到某个线程,因此在您调用sessionFactory.getCurrentSession()
时不会返回该会话。您必须对其进行管理,并确保在会话结束时正确关闭或发生错误。
答案 3 :(得分:0)
如果没有(休眠)会话,您将无法访问数据。
提供此类会话的一种方法是(使用spring时):
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
或org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
(这取决于您使用持久性提供程序的方式)这个fiters的积极副作用是,在呈现JSP视图时会话仍处于打开状态 - 因此在渲染时访问这样一个尚未加载的属性时,您将没有延迟加载问题。