1. 程式人生 > >Spring事物失效、無效問題

Spring事物失效、無效問題

專案原來的ORM是Hibernate,要改造成MyBatis,相關配置後啟動成功,沒有報錯。

資料庫是MySql5.7 表的儲存引擎是:InnoDB

但是在測試事物有效性的時候,發現不回滾!!

@Override
public void saveUser(UserVO vo) {
    UserDao.saveUser(vo);
    throw new RuntimeException("事物異常,請回滾吧。");
}

 

配置如下:

<!-- 啟用註解支援 -->
<context:annotation-config/>
<!-- 開啟aop註解方式 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<!-- ========== Mybatis 配置以及事物的配置 Start ==========-->
<!-- 不需要mybatis的配置對映檔案 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 注入資料來源-->
    <property name="dataSource" ref="dataSource" />
    <!-- 自動掃描對映的xml檔案 -->
    <property name="mapperLocations" value="classpath:com/xx/*/dao/mapper/*.xml"></property>
</bean>
<!-- 自動掃描對映介面類 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    <property name="basePackage" value="com/xx/*/dao"></property>
</bean>

<!-- 配置Spring的事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
<!-- 攔截器方式配置事物  -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="save*" propagation="REQUIRED" read-only="false" />
        <tx:method name="add*" propagation="REQUIRED" read-only="false" />
        <tx:method name="delete*" propagation="REQUIRED" read-only="false" />
        <tx:method name="update*" propagation="REQUIRED" read-only="false" />
        <tx:method name="edit*" propagation="REQUIRED" read-only="false" />

        <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="export*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="*" propagation="SUPPORTS" read-only="true" />
    </tx:attributes>
</tx:advice>
<aop:config>
    <aop:pointcut id="transactionPointcut" expression="execution(* com.xx.xx.service.impl.*.*(..))" />
    <aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionPointcut" />
</aop:config>
<!--支援註解驅動的事務管理,指定預設事務管理器 -->
<tx:annotation-driven order="0" transaction-manager="transactionManager"/>
<!-- ========== Mybatis 配置以及事物的配置 End ==========-->

 

最終的問題出現在component-scan的順序上:

大致是這樣的場景:

專案中原來使用Spring MVC頁面採用JSP。想要優化,但並不打算用其他的模板語言:比如Freemarker、Thymeleaf等。

直接使用HTML檔案,多好啊~,後來我想不需要Controller層了!!模板+資料的形式太死板了。HTML+Restful 靈活多了。

直接就是dao、dao.mapper 、service、service.impl、vo

 

@RequestMapping 就寫在了Service實現層

在applicationContext.xml 中配置自動掃描:

<context:component-scan base-package="com.xx">

啟動正常,但是url訪問卻是404。(;′⌒`)

於是將這段掃描配置移至spring-mvc.xml,能夠正常訪問了。 但是Spring的事物失效了!!

 

web.xml中的配置:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

spring-mvc.xml後面載入的,所以事物的特性被覆蓋了。

 

最終還是使用了,dao、dao.mapper、service、service.impl、controller、vo的結構。

service在applicationContext.xml中掃描,事物也是配置在這個xml檔案裡面的。

<!-- 配置自動掃描的包 -->
<context:component-scan base-package="com">
    <!-- 掃描時跳過 @Controller 註解的JAVA類(控制器) -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

 

controller在spring-mvc.xml中掃描

<!-- controller類支援事物@Transactional -->
<tx:annotation-driven/>

<!--而在springMVC配置檔案中將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>

問題解決,測試事物成功。

controller層,也支援事物,使用註解形式配合,很棒。示例如下:

@Transactional
@ResponseBody
@RequestMapping(value = "/saveUser", method = RequestMethod.GET)
public void saveUser() throws IOException {
    Uservo = new Uservo();
    vo.setUserName("很好");
    vo.setUserBirthday(new Date());
    vo.setUserId("6");
    vo.setUserSalary(500d);
    userService.saveUser(vo);

    vo.setUserId("7");
    userService.saveUser(vo);
    throw new RuntimeException("事物異常,請回滾吧。");
}

後來仔細想了想,程式碼的分層。還是有意義的。controller可以處理頁面邏輯,比如引數接收、處理、url對映這些偏頁面的邏輯。service層則更加註重業務邏輯處理。這樣分開也是很好的。