java Spring & Hibernate:非事务性服务方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4344983/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring & Hibernate: non transactional service methods
提问by toomuchcs
I want my read methods not to use a transaction since this is just not needed at all, I only mark my create/update methods with @Transactional. But how do I do this? I have a pretty basic configuration of Spring with etc...
我希望我的读取方法不使用事务,因为这根本不需要,我只用 @Transactional 标记我的创建/更新方法。但是我该怎么做呢?我有一个非常基本的 Spring 配置等等...
SessionFactoryis injected in my DAO, and in each method I call sessionFactory.getCurrentSession().doQueryStuff();
SessionFactory被注入到我的 DAO 中,并且在我调用 sessionFactory 的每个方法中。getCurrentSession().doQueryStuff();
This, however results in this error:
但是,这会导致此错误:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
If you need my Spring configuration:
如果您需要我的 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 />
Does this error have anything to do with the fact that Propagation is standard Required?
此错误是否与传播是标准必需的这一事实有关?
回答by Javier Ferrero
Mark the method as transactional and read only to ensure the transaction does not modify any data:
将该方法标记为事务性和只读以确保事务不会修改任何数据:
@Transactional(readOnly=true)
This is an useful optimization when working with Hibernate. To read more on the implications of this annotation, here is a great post: Read-Only transactions with Spring and Hibernate
在使用 Hibernate 时,这是一个有用的优化。要阅读有关此注释的含义的更多信息,这里有一篇很棒的文章:使用 Spring 和 Hibernate 的只读事务
回答by Vineeth
As the message clearly says, no session is bound to the thread and the configuration you have specified does NOT allow a "non-transaction" session to be created. I will try to explain each these of scenarios.
正如消息中明确指出的,没有会话绑定到线程,并且您指定的配置不允许创建“非事务”会话。我将尝试解释每一个场景。
When Spring's transaction is enabled in your configuration(as you have done), Spring will wrap the SessionFactory object with a proxy that prevents creation of new sessions, if not already present, when SessionFactory.getCurrentSession is called. The proxy will only get the current session that is bound to the thread local and no ad-hoc session(non-transactional) creation is allowed by your code. This is how your configuration is preventing non-trasactional session creation.
当在您的配置中启用 Spring 的事务时(如您所做的那样),当 SessionFactory.getCurrentSession 被调用时,Spring 将使用代理包装 SessionFactory 对象,以防止创建新会话(如果尚不存在)。代理只会获取绑定到本地线程的当前会话,并且您的代码不允许创建临时会话(非事务性)。这就是您的配置防止非交易会话创建的方式。
When you annotate a method/class with @Transactional, Spring's TransactionInterceptor will create a session and bind it to the current thread when the method is called so that it is available later. Spring's OpenSessionInViewFilter, if enabled, will also bind a session to the current thread. Since you aren't doing any of these, no thread bound session is found.
当您使用@Transactional 注释方法/类时,Spring 的 TransactionInterceptor 将创建一个会话,并在调用该方法时将其绑定到当前线程,以便稍后可用。Spring 的 OpenSessionInViewFilter,如果启用,也会将会话绑定到当前线程。由于您没有执行任何这些操作,因此找不到线程绑定会话。
What you should do is annotate your class with @Transactional(readOnly = True) and then annotate your create/update/delete methods with @Transactional(readOnly = False). It is important that you have a read-only transaction when you are reading data. This assures you that nobody can commit data during that call.
你应该做的是用@Transactional(readOnly = True) 注释你的类,然后用@Transactional(readOnly = False) 注释你的创建/更新/删除方法。在读取数据时,拥有只读事务非常重要。这可以确保您在该调用期间没有人可以提交数据。
回答by Eric
It is possible to start a session outside of a transaction even when using Spring transaction management. Call sessionFactory.openSession()
to get hold of a new session. This session is local in that it is not bound to a thread and so won't be returned when you call sessionFactory.getCurrentSession()
. You'll have to manage it and make sure it's properly closed at the the end of your session or if an error occurs.
即使使用 Spring 事务管理,也可以在事务之外启动会话。呼叫sessionFactory.openSession()
以获取新会话。这个会话是本地的,因为它没有绑定到一个线程,所以当你调用sessionFactory.getCurrentSession()
. 您必须管理它并确保它在会话结束时或发生错误时正确关闭。
回答by Ralph
You can not access the data without an (hibernate) session.
如果没有(休眠)会话,您将无法访问数据。
One way to provide such a session is a (when using spring):
提供此类会话的一种方法是(使用 spring 时):
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
ororg.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
(this depends on the way you use your persistence provider)
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
或者org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
(这取决于您使用持久性提供程序的方式)
The positive side effect of this fiters is, that the session is still open when the JSP Views are rendered - so you will have no lazy loading problems when accessing such a not yet loaded property while rendering.
这个 fiters 的积极副作用是,在渲染 JSP 视图时会话仍然打开 - 因此在渲染时访问此类尚未加载的属性时不会有延迟加载问题。