Spring MVC項目中@Transactional不生效

要解釋清我遇到的情況首先要了解以下幾個知識點:

(Ps:造成@Transactional不生效的原因有很多種,可以參考:https://blog.csdn.net/qq_20597727/article/details/84900994)
1、Spring MVC項目中會有兩個容器初始化,配置了Spring註解(例:@Transactional、@Controller、@Service等註解)的類(class)

  • DispatcherServlet一般用來加載MVC相關的類(本文這個過程簡稱:加載springmvc配置)
// springmvc配置文件在web.xml中如何配置的
 <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
 </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
// springmvc.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: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.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="cn.isdev.ssm.**" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <mvc:annotation-driven/>
</beans>
  • ContextLoaderListener一般用來加載整個Spring相關的類(本文這個過程簡稱:加載spring配置)
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
// spring.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:tx="http://www.springframework.org/schema/tx"
       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.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="cn.isdev.ssm.**">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <mvc:annotation-driven/>
	<!--
        4. 事務管理 : DataSourceTransactionManager dataSource:引用上面定義的數據源
    -->
    <bean id="txManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 5. 使用聲明式事務
         transaction-manager:引用上面定義的事務管理器
     -->
    <tx:annotation-driven transaction-manager="txManager" />
</beans>
  • 爲什麼要分兩個容器進行初始化可以參考文章:https://blog.csdn.net/py_xin/article/details/52052627

2、要使spring註解配置生效需要在springmvc.xml配置中或者spring.xml加入<context:component-scan>標籤,如何配置<context:component-scan>是本文的關鍵

3、spring的配置文件與springmvc的配置文件分開加載,在spring容器初始化的時候,會先加載spring配置(即:web.xml中中的配置),之後再加載springmvc的配置(即:web.xml中中的中的配置)。加載springmvc的配置的時候,如果掃面到spring配置掃描加載過的bean也會重新加載,並覆蓋spring配置掃描加載的bean,但springmvc加載的bean都是沒有aop配置的(@Transactional本事也是一種aop),這樣就會導致配置了@Transactional註解的bean事務失效。那麼要解決@Transaction註解的方法就有了,只要保證配置了@Transactional的bean不被springmvc配置中的<context:component-scan>掃描到即可

解決方案

springmvc.xml

/**
* 1、配置白名單,只掃描controller層bean,其他交給spring.xml初始化
* 2、component-scan:黑白名單默認過濾
* 只配置黑名單(exclude-filter):黑名單內的bean不被初始化,其他的均被初始化
* 只配置白名單(include-filter):默認:::白名單內的bean初始化,既不在白名單也不在黑明單的bean也會被初始化
* 3、要想把component-scan默認過濾關閉,只初始化白名單中的bean,需配置use-default-filters="false"
*/
<context:component-scan base-package="cn.isdev.ssm.**" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

spring.xml

// 掃描時除controller意外的所有bean(這樣就包括配置了@Transaction的service了)
<context:component-scan base-package="cn.isdev.ssm.**">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章