我在Spring + Hibernate应用程序中使用事务注释进行研究。
我使用注释时遇到问题。 我有这样的问题:
No Hibernate Session bound to thread
我的合作伙伴建议我在web.xml中使用此过滤器:
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
我做完之后问题得到了解决。他说我总是在他使用@Transactional
注释时编写这个过滤器。
但在我的旧应用程序中,我发现没有此过滤器使用@Transactional
。它正在运作。
谁可以解释一下?
如果没有此处描述的过滤器,更新
模特课:
@Entity
@Table(name = "RECORDS")
public class Record
{
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.AUTO)
private int recordId;
@Column(name = "VALUE1")
private String vol1;
@Column(name = "VALUE2")
private String vol2;
@Column(name = "VALUE3")
private String vol3;
//////////
get and set
}
更新
迹:
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/crud] threw exception [Request processing failed; nested exception is org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here] with root cause
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:544)
at com.wp.crud.dao.MainDaoImpl.getAllRecords(MainDaoImpl.java:49)
at com.wp.crud.controller.MainServiceImpl.getAllRecords(MainServiceImpl.java:50)
at com.wp.crud.controller.MainController.setupForm(MainController.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
我的java代码:
控制器方法
@RequestMapping(value = "/index")
public String setupForm()
{
mainService.getAllRecords());
}
服务接口
@Transactional
public interface MainService
{
public List<Record> getAllRecords();
}
服务impl
@Service("mainService")
@Transactional
public class MainServiceImpl implements MainService
{
@Autowired
private MainDao mainDao;
@Transactional
public List<Record> getAllRecords()
{
return mainDao.getAllRecords();
}
}
配置:
的web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
data.xml中
<!-- Настраивает управление транзакциями с помощью аннотации @Transactional -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Менеджер транзакций -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<!-- Настройки бина dataSource будем хранить в отдельном файле -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="/WEB-INF/jdbc.properties" />
<!-- Непосредственно бин dataSource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />
<!-- Настройки фабрики сессий Хибернейта -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
根context.xml中
<context:component-scan base-package="com.wp.crud.dao"/>
<context:component-scan base-package="com.wp.crud.controller"/>
<!--
Файл с настройками ресурсов для работы с данными (Data Access Resources)
-->
<import resource="data.xml"/>
servlet的context.xml中
<annotation-driven />
<!-- Всю статику (изображения, css-файлы, javascript) положим в папку webapp/resources и замаппим их на урл вида /resources/** -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Отображение видов на jsp-файлы, лежащие в папке /WEB-INF/views -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!-- Файл с настройками контроллеров -->
<beans:import resource="controllers.xml" />
controllers.xml
<context:component-scan base-package="com.wp.crud.controller"/>
P.S。
位于控制器包中的服务。
答案 0 :(得分:1)
如果您需要或想要使用,OpenSessionInViewFilter
取决于您的代码。如果您在视图中使用域对象并具有延迟加载集合(默认值)或引用,则需要使用此过滤器。默认情况下,hibernate会话在完成@Transactional
后消失了,但是为了执行延迟加载,需要一个hibernate会话。 OpenSessionInViewFilter
会保持会话处于打开状态,直到呈现视图为止。
如果您没有任何懒惰或具有特定查询/方法来检索呈现视图所需的所有数据(即强制急切地使用HQL查询获取集合或对象),则不需要{{1 }}
因此,您是否需要它取决于您的用例和技术选择。
您的案例中的问题是您正在扫描同一个包两次。这会导致重复的bean实例(OpenSessionInViewFilter
中的一个实例和ContextLoaderListener
中的一个实例,第一个是您要使用的bean,但由于重复,第二个是您获得的bean。第一个是应用了交易的那个。
将组件扫描元素更改为以下
<强>根context.xml中强>
DispatcherServlet
<强> controllers.xml 强>
<context:component-scan base-package="com.wp.crud">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
这将使<context:component-scan base-package="com.wp.crud" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>
加载所有BUT ContextLoaderListener
注释bean,而@Controller
只加载DispatcherServlet
注释bean。
答案 1 :(得分:0)
您应使用@Transactional
标记必要的方法,以定义开始/结束交易的位置。
在您的应用程序上下文中,您应该定义它的注释驱动并定义要扫描的基础包。因此,Spring使用Proxies扫描标记为@Transactional
的包和包装方法,以启动和提交/ rollbacck事务。