SpringMVC 事务配置完全详解

1.本设计采用springMVC+Hibernate ,事务控制在Service层,直接上代码

2.web.xml

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    version="2.5"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <filter>
        <filter-name>encodingFilter</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>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <servlet-name>spring</servlet-name>
    </filter-mapping>
    <filter>
        <filter-name>openSessionInViewFilter</filter-name>
        <filter-class>
            org.springframework.orm.hibernate4.support.OpenSessionInViewFilter
        </filter-class>
    </filter>
    <filter-mapping>
        <filter-name>openSessionInViewFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <servlet>
        <servlet-name>springMVC3</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>springMVC3</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <session-config>  
        <session-timeout>20</session-timeout>  
    </session-config>
    
    <display-name>MeatBall</display-name>
    <welcome-file-list>
        <welcome-file>/admin/homepage</welcome-file>
    </welcome-file-list>
</web-app>


2. applicationContext.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:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-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/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/task 
        http://www.springframework.org/schema/task/spring-task-3.0.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
        
    <context:annotation-config />

    <!-- 扫描Controller,Service,Reponsitory -->
    <context:component-scan base-package="com.zxd" >
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />

      <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />

      <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />


    </context:component-scan>

    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:resources.properties</value>
            </list>
        </property>
    </bean>

    <!-- 数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="${connection.driver_class}" />
        <property name="jdbcUrl" value="${connection.url}" />
        <property name="user" value="${connection.username}" />
        <property name="password" value="${connection.password}" />
        <property name="maxPoolSize" value="80" />
        <property name="minPoolSize" value="1" />
        <property name="initialPoolSize" value="1" />
        <property name="maxIdleTime" value="20" />
    </bean>
    
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan">
            <list>
                <value>com.zxd.project.goods.model</value>
                <value>com.zxd.project.user.model</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.jdbc.batch_size">20</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <bean id="txManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="create*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
            <tx:method name="upload*" propagation="REQUIRED" />
            <tx:method name="merge*" propagation="REQUIRED" />
            <tx:method name="del*" propagation="REQUIRED" />
            <tx:method name="remove*" propagation="REQUIRED" />
            <tx:method name="clear*" propagation="REQUIRED" />
            <tx:method name="put*" propagation="REQUIRED" />
            <tx:method name="use*" propagation="REQUIRED" />
            <tx:method name="get*" propagation="REQUIRED" read-only="true" />
            <tx:method name="load*" propagation="REQUIRED" read-only="true" />
            <tx:method name="count*" propagation="REQUIRED" read-only="true" />
            <tx:method name="find*" propagation="REQUIRED" read-only="true" />
            <tx:method name="after*" propagation="REQUIRED" read-only="true" />
            <tx:method name="list*" propagation="REQUIRED" />
            <tx:method name="pag*" propagation="REQUIRED" />
            <tx:method name="query*" propagation="REQUIRED" read-only="true" />
        </tx:attributes>
    </tx:advice>

    <!-- 只对业务逻辑(service)层实施事务 -->
    <aop:config>
        <aop:pointcut id="txPointcut" 
            expression="execution(* com.zxd..service.*.*(..))" />
        <aop:advisor  advice-ref="txAdvice" pointcut-ref="txPointcut" />
    </aop:config>
</beans>

 3.application-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:sec="http://www.springframework.org/schema/security" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:task="http://www.springframework.org/schema/task" 
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd   
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/security  
        http://www.springframework.org/schema/security/spring-security-3.2.xsd
        http://www.springframework.org/schema/task  
        http://www.springframework.org/schema/task/spring-task-3.1.xsd ">

    <!-- 注解驱动 -->
    <mvc:annotation-driven>  
        <mvc:message-converters>
            <!-- 中文编码 -->
            <bean class="com.zxd.common.util.UTF8StringHttpMessageConverter" />  
        </mvc:message-converters>  
    </mvc:annotation-driven> 
    
    <!-- 定时任务驱动 --> 
    <task:annotation-driven/>  
    
    <context:component-scan base-package="com.zxd" >
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
    
    <!-- 视图解析 -->
    <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <!-- 返回的视图模型数据需要经过jstl来处理 -->
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/WEB-INF/jsp" />
        <property name="suffix" value=".jsp" />
    </bean>

    <!-- 对静态资源文件的访问 不支持访问WEB-INF目录 -->
    <mvc:default-servlet-handler />

    <!-- 对静态资源文件的访问 支持访问WEB-INF目录 -->
    <mvc:resources location="/static/" mapping="/static/**" />
    
    <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="500000000" />
    </bean>

    <bean id="stringConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
                <value>text/plain;charset=UTF-8</value>
            </list>
        </property>
    </bean>

    <!-- 输出对象转JSON支持 -->
    <bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="stringConverter"/>
                <ref bean="jsonConverter" />
            </list>
        </property>
    </bean>
    
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean id="ErrorInterceptor" class="com.zxd.common.interceptors.GlobleErrorInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
    
</beans>

4.以下为详解。

首先通过web.xml解析applicationContext(此为父容器)

    <!-- 扫描Controller,Service,Reponsitory -->
    <context:component-scan base-package="com.zxd" >
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />

      <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />

      <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />


    </context:component-scan>

在这段代码中,首先会吧com.zxd下的Controller,Service,Repository,注入到父容器中可以不写Service,Repository,Controller,直接写成

<context:component-scan base-package="com.zxd" />也是可以的,Component-scan中就包含Service,Repository,Controller这一些注解,父容器是有事务控制的。

然后再来看
 <context:component-scan base-package="com.zxd" >
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>
这段代码,在加载applicationContext-servlet.xml中一定要除去Service层,防止再次注入到父容器中,这个applicationContext-servlet是不具备事务控制的。

下面,摘一段控制台打印信息。


可以看到创建了食物,而且我在update*的isolation处改变了隔离级别。事务配置成功。那么下面再来看一下失败的。

 在这里,我们可以看到,rollingBack,事务回滚成功。

如果您还想更深入了解,例如源码等,请捐赠我任意一笔金额。谢谢

原文地址:https://www.cnblogs.com/weizizhe/p/5033158.html