首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

由OpenSessionInViewFilter报错引出的spring3.0事务配置有关问题及解决方法

2012-08-28 
由OpenSessionInViewFilter报错引出的spring3.0事务配置问题及解决办法开发环境IDE: eclipse3.4FrameWork:

由OpenSessionInViewFilter报错引出的spring3.0事务配置问题及解决办法
开发环境

IDE: eclipse3.4
FrameWork: spring3.0 + spring mvc 3.0 + hibernate 3.2
Server: Tomcat 6.0

使用 OpenSessionInViewFilter的原因

<context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>

hibernate及数据源的配置

<bean id="sessionFactory" ref="dataSource"/>   <property name="packagesToScan" value="com"/>                 <property name="hibernateProperties"><props>            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>    <!--  <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>--><!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> --><prop key="hibernate.show_sql">true</prop><prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop><prop key="hibernate.cache.use_query_cache">true</prop><prop key="hibernate.hbm2ddl.auto">update</prop><prop key="hibernate.format_sql">true</prop><prop key="hibernate.use_sql_comments">true</prop><!--  <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop><prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>--></props>    </property> </bean>


配置transactionManager管理事务
<bean id="transactionManager" autowire="byName"/>


接下来是 自动化事务
<tx:annotation-driven/>

如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该如下配置
<tx:annotation-driven transaction-manager="txManager"/>


这里需要注意的问题,看过spring的参考手册的朋友都会这样配置
<context:component-scan base-package="com">

因为省事,一句话可以自动把com包低下的所有带annotation注解的类都实例化并配好了,但如果这样简单的配置会导致刚才spring的事务配置失效
原因:
实例化@Controller类时,Spring会自动把关联的@Service(此@Service已做了@Transaction事务注解)类实例化,此时事务并未生效,导致@Transaction注解无效,事务未被注册

因此需要把@Controller和其它的@Service,@Components,@Reposity等分开实例化,在事务生效后,并且其它组件都实例化完成后,@Controller最后实例化,app-config.xml和mvc-config.xml的配置分别如下

app-config.xml
   <!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 -->   <context:component-scan base-package="com">         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>     </context:component-scan
>

mvc-config.xml(注意里面的注释)
 <!-- 扫描com及子包,自动实例化带@controller注释的实例,      由于实例化controller时会对controller关联的Service类一同实例化,所以这里需要排除@Service  --><context:component-scan base-package="com">   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/></context:component-scan>



此时在带@Service注解的类中添加@Transactional标签就会其作用了,例如
@Service("articleService")@Transactionalpublic class ArticleService extends GenericService<Article, Long> {               @Autowiredprivate ArticleDao articleDao;        @Transactional(readOnly=true)        public List<Article> getArticles(){          /*...*/        }                @Transactional(propagation=Propagation.REQUIRED)        public void saveArticle(long id){            /*..*/        }}

更多事务注解的方式请参考spring3.0 reference

这这样需要对每个Service的方法都要做类似的注解,多了会很麻烦,也难管理维护。

下面通过spring的aop对事务进行自动化管理,配置如下
<!-- 配置aop 切入点 和事务访问策略 -->   <aop:config>  <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/>       <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/></aop:config><tx:advice id="txAdvice" > <tx:attributes><tx:method name="del*" propagation="REQUIRED"/><tx:method name="save*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="add*" propagation="REQUIRED"/><tx:method name="create*" propagation="REQUIRED"/><tx:method name="get*" read-only="true"/><tx:method name="*"/></tx:attributes></tx:advice>  
 

注意
1这部分代码要放在<tx:annotation-driven/>的上面,否则tx:advice不起作用
2<tx:advice id="txAdvice" > 如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该修改为 <tx:advice id="txAdvice" transaction-manager="txManager" >


app-config.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:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/tx        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">               <!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 -->   <context:component-scan base-package="com">         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>     </context:component-scan>                    <bean id="propertyConfigurer" destroy-method="close">  <property name="driverClass"><value>${jdbc.driverClass}</value></property>  <property name="jdbcUrl"><value>${jdbc.jdbcUrl}</value></property>  <property name="user"><value>${jdbc.user}</value></property>  <property name="password"><value>${jdbc.password}</value></property>  <property name="minPoolSize"><value>${jdbc.minPoolSize}</value></property>  <property name="maxPoolSize"><value>${jdbc.maxPoolSize}</value></property>  <property name="maxIdleTime"><value>${jdbc.maxIdleTime}</value></property></bean>             <!--  hibernate.hbm2ddl.auto参数说明validate           加载hibernate时,验证创建数据库表结构 create             每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。 create-drop        加载hibernate时创建,退出是删除表结构  update             加载hibernate自动更新数据库结构  none               不更新数据库结构    -->    <bean id="sessionFactory" ref="dataSource"/>   <property name="packagesToScan" value="com"/>                 <property name="hibernateProperties"><props>            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>    <!--  <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>--><!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> --><prop key="hibernate.show_sql">true</prop><prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop><prop key="hibernate.cache.use_query_cache">true</prop><prop key="hibernate.hbm2ddl.auto">update</prop><prop key="hibernate.format_sql">true</prop><prop key="hibernate.use_sql_comments">true</prop><!--  <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop><prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>--></props>    </property> </bean>            <!-- 配置hibernate事务 -->    <bean id="transactionManager" autowire="byName"/>           <!-- 配置aop 切入点 和事务访问策略 -->   <aop:config>  <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/>       <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/></aop:config><tx:advice id="txAdvice" > <tx:attributes><tx:method name="del*" propagation="REQUIRED"/><tx:method name="save*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="add*" propagation="REQUIRED"/><tx:method name="create*" propagation="REQUIRED"/><tx:method name="get*" read-only="true"/><tx:method name="*"/></tx:attributes></tx:advice>            <!-- tx:annotation 自动配置事务,注意这个标签必需放在tx:advice下面,否则不起作用 -->    <tx:annotation-driven/>            <!-- Application Message Bundle --><bean id="messageSource" value="/WEB-INF/messages/messages" /><property name="cacheSeconds" value="0" /></bean><!-- Configures Spring MVC <import resource="mvc-config.xml" />--></beans>
















<?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:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean /> </property> </bean> <bean id="stringHttpMessageConverter" expression="org.springframework.stereotype.Controller"/> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/></context:component-scan><!-- Forwards requests to the "/" resource to the "welcome" view --><mvc:view-controller path="/" view-name="welcome"/><!-- Configures Handler Interceptors --><mvc:interceptors><!-- Changes the locale when a 'locale' request parameter is sent; e.g. /?locale=de --><bean /></mvc:interceptors><!-- Saves a locale change using a cookie --><bean id="localeResolver" /><!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory --><bean value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/></bean></beans>


这是web.xml的基本配置
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">  <display-name>spring-security-base</display-name>  <welcome-file-list>    <welcome-file>index.html</welcome-file>    <welcome-file>index.htm</welcome-file>    <welcome-file>index.jsp</welcome-file>    <welcome-file>default.html</welcome-file>    <welcome-file>default.htm</welcome-file>    <welcome-file>default.jsp</welcome-file>  </welcome-file-list>       <context-param>        <param-name>contextConfigLocation</param-name>        <param-value>          /WEB-INF/spring/security.xml          /WEB-INF/spring/app-config.xml        </param-value>    </context-param>        <!-- spring security 过滤器链 -->    <filter>        <filter-name>springSecurityFilterChain</filter-name>        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>    </filter>    <filter-mapping>        <filter-name>springSecurityFilterChain</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>    <listener>        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>    </listener>                    <!-- Reads request input using UTF-8 encoding --><filter><filter-name>characterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>characterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>  <!-- for restful style 注意要放在 characterEncodingFilter 否则可能引起不必要的乱码--> <filter>  <filter-name>httpMethodFilter</filter-name>  <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class></filter><filter-mapping> <filter-name>httpMethodFilter</filter-name> <url-pattern>/*</url-pattern></filter-mapping>          <!--OpenSessionInViewFilter 作用,防止hibernate lazy-load 引起的不在同一session的报错  -->    <filter>        <filter-name>hibernateFilter</filter-name>         <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>hibernateFilter</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>                        <!-- Enables clean URLs with JSP views e.g. /welcome instead of /app/welcome      注意:     过滤器执行顺序是按web.xml中的各过滤器的位置顺序执行的     将其它过滤器放在此过滤器的前面,否则由于url重写,会导致其它过滤器过滤的url失效--><filter><filter-name>UrlRewriteFilter</filter-name><filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class><!--   <init-param>                  <param-name>logLevel</param-name>                  <param-value>DEBUG</param-value>          </init-param>        -->    </filter><filter-mapping><filter-name>UrlRewriteFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>                             <!-- Handles all requests into the application --><servlet><servlet-name>springMVCBase</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    <init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring/mvc-config.xml</param-value></init-param><load-on-startup>2</load-on-startup></servlet><servlet-mapping><servlet-name>springMVCBase</servlet-name><url-pattern>/app/*</url-pattern></servlet-mapping>     </web-app>


很抱歉,由于我的项目里还有很多其它的依赖,又没有用maven做管理,现在放出来可能也无法运行。你可以用svn把spring的的在线例子下载下来看。我的配置大部分是参考里面的 mvc-base 和 mvc-ajax这两个例子,在其基础上增加了spring security和事务管理等

这是spirng samples的 svn地址 https://src.springframework.org/svn/spring-samples/





<ul> <c:forEach var="article" items="${group.articles}"> <li>${article.title}</li> </c:forEach> </ul>

我对spring aop和事务控制的理解也很肤浅,在我看来,无论你把@Transcational放在哪,最终都是通过HibernateSessionFactory起作用,放在service是为了保证里面有多个数据更新时,如果失败可以保证整体数据的回滚,当然是否正确的回滚还需再测试,我会在测试后把结果贴出来
<ul> <c:forEach var="article" items="${group.articles}"> <li>${article.title}</li> </c:forEach> </ul>

我对spring aop和事务控制的理解也很肤浅,在我看来,无论你把@Transcational放在哪,最终都是通过HibernateSessionFactory起作用,放在service是为了保证里面有多个数据更新时,如果失败可以保证整体数据的回滚,当然是否正确的回滚还需再测试,我会在测试后把结果贴出来

我的意思是在control中如果使用了如下的情况,延迟加载是失败的 该如何解决?
control:
login 方法:
1、User user=userservice.findbyNameAndpassword();//此处用事务获取了实体
方法执行完后,事务管理会关闭session
2、紧接着如果再用user.getUserGroup().getRules()则报延迟加载错误的问题了。

所以想把事务加载在control层,该如何操作呢?&lt;web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"&gt;
  &lt;display-name&gt;ceoms_v3&lt;/display-name&gt;
 
  &lt;filter&gt;
    &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;
    &lt;filter-class&gt;org.springframework.orm.hibernate3.support.OpenSessionInViewFilter&lt;/filter-class&gt;
  &lt;/filter&gt;
  &lt;filter-mapping&gt;
    &lt;filter-name&gt;hibernateFilter&lt;/filter-name&gt;
    &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
  &lt;/filter-mapping&gt;
 
  &lt;listener&gt;
    &lt;description&gt;
Used to cleanup when a session is destroyed&lt;/description&gt;
    &lt;display-name&gt;ZK Session cleaner&lt;/display-name&gt;
    &lt;listener-class&gt;org.zkoss.zk.ui.http.HttpSessionListener&lt;/listener-class&gt;
  &lt;/listener&gt;
  &lt;servlet&gt;
    &lt;description&gt;
The ZK loader for ZUML pages&lt;/description&gt;
    &lt;servlet-name&gt;zkLoader&lt;/servlet-name&gt;
    &lt;servlet-class&gt;org.zkoss.zk.ui.http.DHtmlLayoutServlet&lt;/servlet-class&gt;
    &lt;init-param&gt;
      &lt;param-name&gt;update-uri&lt;/param-name&gt;
      &lt;param-value&gt;/zkau&lt;/param-value&gt;
    &lt;/init-param&gt;
    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
  &lt;/servlet&gt;
  &lt;servlet&gt;
    &lt;description&gt;
The asynchronous update engine for ZK&lt;/description&gt;
    &lt;servlet-name&gt;auEngine&lt;/servlet-name&gt;
    &lt;servlet-class&gt;org.zkoss.zk.au.http.DHtmlUpdateServlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;zkLoader&lt;/servlet-name&gt;
    &lt;url-pattern&gt;*.zul&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;zkLoader&lt;/servlet-name&gt;
    &lt;url-pattern&gt;*.zhtml&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;auEngine&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/zkau/*&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
  &lt;welcome-file-list&gt;
    &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;
    &lt;welcome-file&gt;index.htm&lt;/welcome-file&gt;
    &lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;
    &lt;welcome-file&gt;default.html&lt;/welcome-file&gt;
    &lt;welcome-file&gt;default.htm&lt;/welcome-file&gt;
    &lt;welcome-file&gt;default.jsp&lt;/welcome-file&gt;
    &lt;welcome-file&gt;index.zul&lt;/welcome-file&gt;
  &lt;/welcome-file-list&gt;
  &lt;error-page&gt;
    &lt;error-code&gt;404&lt;/error-code&gt;
    &lt;location&gt;/404.zul&lt;/location&gt;
  &lt;/error-page&gt;
  &lt;error-page&gt;
    &lt;exception-type&gt;java.lang.Throwable&lt;/exception-type&gt;
    &lt;location&gt;/error.zul&lt;/location&gt;
  &lt;/error-page&gt;
  &lt;context-param&gt;
    &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
    &lt;param-value&gt;/WEB-INF/classes/applicationContext.xml;&lt;/param-value&gt;
  &lt;/context-param&gt;
  &lt;filter&gt;
    &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
    &lt;filter-class&gt;org.springframework.web.filter.CharacterEncodingFilter&lt;/filter-class&gt;
    &lt;init-param&gt;
      &lt;param-name&gt;encoding&lt;/param-name&gt;
      &lt;param-value&gt;utf-8&lt;/param-value&gt;
    &lt;/init-param&gt;
  &lt;/filter&gt;
  &lt;filter-mapping&gt;
    &lt;filter-name&gt;encodingFilter&lt;/filter-name&gt;
    &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
  &lt;/filter-mapping&gt;

  &lt;servlet&gt;
    &lt;servlet-name&gt;proxool&lt;/servlet-name&gt;
    &lt;servlet-class&gt;org.logicalcobwebs.proxool.admin.servlet.AdminServlet&lt;/servlet-class&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;proxool&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/proxool&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
  &lt;listener&gt;
    &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
  &lt;/listener&gt;
&lt;/web-app&gt;</pre>
<p>?</p>
<p>我已经放在最前面了..还是不行...</p>  </bean>    
</mvc:interceptors>     </bean>    
</mvc:interceptors>  

我用的不是springMVC,而且所有的dao和service都是注解形式,所以不知道在哪里配置OpenSessionInViewInterceptor <context:component-scan base-package="com"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>

hibernate及数据源的配置
<bean id="sessionFactory" ref="dataSource"/>   <property name="packagesToScan" value="com"/>                 <property name="hibernateProperties"><props>            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>    <!--  <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>--><!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> --><prop key="hibernate.show_sql">true</prop><prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop><prop key="hibernate.cache.use_query_cache">true</prop><prop key="hibernate.hbm2ddl.auto">update</prop><prop key="hibernate.format_sql">true</prop><prop key="hibernate.use_sql_comments">true</prop><!--  <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop><prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>--></props>    </property> </bean>


配置transactionManager管理事务
<bean id="transactionManager" autowire="byName"/>


接下来是 自动化事务
<tx:annotation-driven/>

如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该如下配置
<tx:annotation-driven transaction-manager="txManager"/>


这里需要注意的问题,看过spring的参考手册的朋友都会这样配置
<context:component-scan base-package="com">

因为省事,一句话可以自动把com包低下的所有带annotation注解的类都实例化并配好了,但如果这样简单的配置会导致刚才spring的事务配置失效
原因:
实例化@Controller类时,Spring会自动把关联的@Service(此@Service已做了@Transaction事务注解)类实例化,此时事务并未生效,导致@Transaction注解无效,事务未被注册

因此需要把@Controller和其它的@Service,@Components,@Reposity等分开实例化,在事务生效后,并且其它组件都实例化完成后,@Controller最后实例化,app-config.xml和mvc-config.xml的配置分别如下

app-config.xml
   <!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 -->   <context:component-scan base-package="com">         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>     </context:component-scan
>

mvc-config.xml(注意里面的注释)
 <!-- 扫描com及子包,自动实例化带@controller注释的实例,      由于实例化controller时会对controller关联的Service类一同实例化,所以这里需要排除@Service  --><context:component-scan base-package="com">   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/></context:component-scan>



此时在带@Service注解的类中添加@Transactional标签就会其作用了,例如
@Service("articleService")@Transactionalpublic class ArticleService extends GenericService<Article, Long> {               @Autowiredprivate ArticleDao articleDao;        @Transactional(readOnly=true)        public List<Article> getArticles(){          /*...*/        }                @Transactional(propagation=Propagation.REQUIRED)        public void saveArticle(long id){            /*..*/        }}

更多事务注解的方式请参考spring3.0 reference

这这样需要对每个Service的方法都要做类似的注解,多了会很麻烦,也难管理维护。

下面通过spring的aop对事务进行自动化管理,配置如下
<!-- 配置aop 切入点 和事务访问策略 -->   <aop:config>  <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/>       <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/></aop:config><tx:advice id="txAdvice" > <tx:attributes><tx:method name="del*" propagation="REQUIRED"/><tx:method name="save*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="add*" propagation="REQUIRED"/><tx:method name="create*" propagation="REQUIRED"/><tx:method name="get*" read-only="true"/><tx:method name="*"/></tx:attributes></tx:advice>  
 

注意
1这部分代码要放在<tx:annotation-driven/>的上面,否则tx:advice不起作用
2<tx:advice id="txAdvice" > 如果前面配置的事务id不是"transactionManager",比如id="txManager",则应该修改为 <tx:advice id="txAdvice" transaction-manager="txManager" >


app-config.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:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/tx        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd        http://www.springframework.org/schema/aop        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">               <!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,所有controller的实例化在 mvc-config中完成 -->   <context:component-scan base-package="com">         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>     </context:component-scan>                    <bean id="propertyConfigurer" destroy-method="close">  <property name="driverClass"><value>${jdbc.driverClass}</value></property>  <property name="jdbcUrl"><value>${jdbc.jdbcUrl}</value></property>  <property name="user"><value>${jdbc.user}</value></property>  <property name="password"><value>${jdbc.password}</value></property>  <property name="minPoolSize"><value>${jdbc.minPoolSize}</value></property>  <property name="maxPoolSize"><value>${jdbc.maxPoolSize}</value></property>  <property name="maxIdleTime"><value>${jdbc.maxIdleTime}</value></property></bean>             <!--  hibernate.hbm2ddl.auto参数说明validate           加载hibernate时,验证创建数据库表结构 create             每次加载hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。 create-drop        加载hibernate时创建,退出是删除表结构  update             加载hibernate自动更新数据库结构  none               不更新数据库结构    -->    <bean id="sessionFactory" ref="dataSource"/>   <property name="packagesToScan" value="com"/>                 <property name="hibernateProperties"><props>            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>    <!--  <prop key="hibernate.dialect">org.hibernate.dialect.sql</prop>--><!-- <prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop> --><prop key="hibernate.show_sql">true</prop><prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop><prop key="hibernate.cache.use_query_cache">true</prop><prop key="hibernate.hbm2ddl.auto">update</prop><prop key="hibernate.format_sql">true</prop><prop key="hibernate.use_sql_comments">true</prop><!--  <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop><prop key="hibernate.search.default.indexBase">/WEB-INF/indexes</prop>--></props>    </property> </bean>            <!-- 配置hibernate事务 -->    <bean id="transactionManager" autowire="byName"/>           <!-- 配置aop 切入点 和事务访问策略 -->   <aop:config>  <aop:pointcut id="serviceOperation" expression="execution(* com.*.service..*Service.*(..))"/>       <aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/></aop:config><tx:advice id="txAdvice" > <tx:attributes><tx:method name="del*" propagation="REQUIRED"/><tx:method name="save*" propagation="REQUIRED"/><tx:method name="update*" propagation="REQUIRED"/><tx:method name="add*" propagation="REQUIRED"/><tx:method name="create*" propagation="REQUIRED"/><tx:method name="get*" read-only="true"/><tx:method name="*"/></tx:attributes></tx:advice>            <!-- tx:annotation 自动配置事务,注意这个标签必需放在tx:advice下面,否则不起作用 -->    <tx:annotation-driven/>            <!-- Application Message Bundle --><bean id="messageSource" value="/WEB-INF/messages/messages" /><property name="cacheSeconds" value="0" /></bean><!-- Configures Spring MVC <import resource="mvc-config.xml" />--></beans>

















19 楼 bushkarl 2010-09-10   很棒 , 正在纳闷怎么在spring3mvc 加入opensessioninfilter。哈哈,看了你的文章,我成功了 !

热点排行