我尝试使用Spring,rest,Hibernate创建一个小例子。为了在编组完成时打开会话,我在web.xml中添加了过滤器org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
然而,现在,我受到严重困扰,这可能是因为我对AOP很新。我面临的问题是,当发送请求时会话未打开:
20.10.2011 17:26:40 org.apache.catalina.core.StandardWrapperValve invoke
SCHWERWIEGEND: Servlet.service() for servlet mvc-dispatcher threw exception
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:685)
我认为这与Spring + Hibernate with annotations: No Hibernate Session bound to thread中描述的问题相同,但我没有让它发挥作用。
的web.xml:
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring Web MVC Application</display-name>
<filter>
<filter-name>SessionPerRequest</filter-name>
<filter-class>
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionPerRequest</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
MVC-调度-servlet.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="backend"/>
<property name="password" value="bUWGRysbbzYuXsbq" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="de.company.springtest" />
<mvc:annotation-driven />
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- <aop:config> -->
<!-- <aop:advisor pointcut="execution(* de.company.springtest..*.*(..))" advice-ref="txAdvice" /> -->
<!-- </aop:config> -->
</beans>
如果aop部分被取消注释(这是另一个线程中的解决方案),它会在启动时抛出以下异常:
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@46e06703: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,dataSource,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,JSONController,hibernateConfiguration,org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0,org.springframework.format.support.FormattingConversionServiceFactoryBean#0,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#0,org.springframework.web.servlet.handler.MappedInterceptor#0,sessionFactory,transactionManager,txAdvice,org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0,sessionFactoryBean]; root of factory hierarchy
20.10.2011 17:37:04 org.springframework.web.context.ContextLoader initWebApplicationContext
SCHWERWIEGEND: Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in ServletContext resource [/WEB-INF/mvc-dispatcher-servlet.xml]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor': Cannot resolve reference to bean 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0' while setting bean property 'transactionAttributeSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0': BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:452)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
休息控制器,但尚未被调用。因此,不会在函数的最开始处调用断点。
package de.company.springtest.controller;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.classic.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import de.company.springtest.Item;
import de.company.springtest.Order;
@Controller
@RequestMapping("/user")
// localhost:8080/RESTfulTest/rest/user/abc
public class JSONController {
@Autowired
private SessionFactory sessionFactory;
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody
Order postOrderInJSON() {
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Order order = new Order();
order.getItems().add(new Item());
session.save(order);
// session.flush();
transaction.commit();
// session.close();
return order;
}
@RequestMapping(value = "get/{id}", method = RequestMethod.GET)
public @ResponseBody
Order getUserInJSON(/* @PathVariable Long id */) {
Session session = sessionFactory.getCurrentSession();
Transaction transaction = session.beginTransaction();
Order order = new Order();
order.getItems().add(new Item());
session.save(order);
// session.flush();
transaction.commit();
// session.close();
return order;
}
}
HibernateConfiguration.java
package de.company.springtest;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.dialect.MySQLDialect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate3.HibernateTransactionManager;
import org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;
@Configuration
public class HibernateConfiguration {
@Value("#{dataSource}")
private DataSource dataSource;
@Bean
public AnnotationSessionFactoryBean sessionFactoryBean() {
Properties props = new Properties();
props.put("hibernate.dialect", MySQLDialect.class.getName());
props.put("hibernate.current_session_context_class", "thread");
props.put("hibernate.transaction.factory_class", "org.hibernate.transaction.JDBCTransactionFactory");
props.put("hibernate.format_sql", "true");
AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean();
bean.setAnnotatedClasses(new Class[]{Item.class, Order.class});
bean.setHibernateProperties(props);
bean.setDataSource(this.dataSource);
bean.setSchemaUpdate(true);
return bean;
}
@Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager hibernateTransactionManager = new HibernateTransactionManager( sessionFactoryBean().getObject() );
return hibernateTransactionManager;
}
}
你有什么建议我可以继续搜索吗?
答案 0 :(得分:2)
取消注释零件时的错误很可能是由类路径中缺少aspectj引起的。
或者,您可以在DAO中使用@Transactional注释,或者在应用程序设计中开始/结束事务适合的位置,因为链接线程中的第一个注释指出。您需要使用其中任何一个来启动事务(或手动执行) - 仅配置事务管理器是不够的。
答案 1 :(得分:0)
嵌套异常是java.lang.NoClassDefFoundError:org / aspectj / weaver / reflect / ReflectionWorld $ ReflectionWorldException
您需要将aspectJ(aspectjweaver.jar)与您的应用程序一起部署。
如果您使用maven而不是将其添加到您的pom:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.9</version>
</dependency>
如果您不使用maven,请手动添加这两个罐子。
答案 2 :(得分:0)
您的整个配置/布线看起来非常“原始”。这种异常的原因=&gt;你的“服务层”没有被处理,因此Hibernate抱怨。
不要将@Transactional置于DAO级别,因为有人建议=&gt;这是错误的。您应该始终在业务单位上进行交易=&gt;在服务层。
看一下将Spring和Hibernate集成在一起的example project(只是克隆它)。
实际上有一个HibernateSessionNotBoundToThreadIntegrationTest显示了此异常的原因。
这是通过Spring AOP正确TX配置的example:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<aop:config>
<aop:pointcut id="moneyMakingBusinessServiceMethods"
expression="execution(* org.gitpod.startup.service.MoneyMakingBusinessService.*(..))"/>
<aop:advisor advice-ref="moneyMakingAdvice"
pointcut-ref="moneyMakingBusinessServiceMethods"/>
</aop:config>
<tx:advice id="moneyMakingAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="makeMoney" propagation="REQUIRED"/>
<tx:method name="withdrawMoney" propagation="REQUIRED" read-only="true"/>
<tx:method name="*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
</beans>