使用SSM框架進(jìn)行項(xiàng)目開(kāi)發(fā)時(shí),經(jīng)常因?yàn)榕渲玫膯?wèn)題瓢剿,可能會(huì)遇到一些稀奇古怪的問(wèn)題,比如說(shuō):明明已經(jīng)配置了事務(wù)管理泳姐,并且也在需要進(jìn)行事務(wù)控制的方法上添加了@Transactional
注解度苔,服務(wù)也基本能夠正常啟動(dòng)和使用匆篓,但是當(dāng)事務(wù)控制的方法中出錯(cuò)時(shí),之前執(zhí)行的修改數(shù)據(jù)庫(kù)的操作寇窑,沒(méi)有被回滾鸦概。
另外事務(wù)控制失效的另一個(gè)明顯表現(xiàn)就是任何一個(gè)改變數(shù)據(jù)庫(kù)數(shù)據(jù)的操作,都會(huì)直接被提交疗认,即操作一經(jīng)執(zhí)行完残,就可以立馬在數(shù)據(jù)庫(kù)中得以體現(xiàn)。
事務(wù)控制未生效的配置横漏。
springmvc配置文件指定掃包路徑
<context:component-scan base-package="com.alex"> #錯(cuò)誤配置方式
spirng-mybatis配置文件
# 沒(méi)有引入掃包規(guī)則
<!-- 引入數(shù)據(jù)庫(kù)配置文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties" />
</bean>
<!-- 數(shù)據(jù)庫(kù)配置 -->
<bean id="dataSource" class="com.alex.common.tools.DBConnection"
destroy-method="close">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- 初始化連接大小 -->
<property name="initialSize" value="${initialSize}"></property>
<!-- 連接池最大數(shù)量 -->
<property name="maxActive" value="${maxActive}"></property>
<!-- 連接池最大空閑 -->
<property name="maxIdle" value="${maxIdle}"></property>
<!-- 連接池最小空閑 -->
<property name="minIdle" value="${minIdle}"></property>
<!-- 獲取連接最大等待時(shí)間 -->
<property name="maxWait" value="${maxWait}"></property>
</bean>
<!-- spring和MyBatis完美整合谨设,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--引入mybatis-config.xml-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 自動(dòng)掃描mapping.xml文件 -->
<property name="mapperLocations" value="classpath*:com/alex/ai/nlpc/mapper/*/*.xml"></property>
</bean>
<!-- DAO接口所在包名,Spring會(huì)自動(dòng)查找其下的類 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--basePackage指定要掃描的包缎浇,在此包之下的映射器都會(huì)被搜索到扎拣。 可指定多個(gè)包,包與包之間用逗號(hào)或分號(hào)分隔 -->
<property name="basePackage" value="com.alex.ai.nlpc.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- (事務(wù)管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置基于注解的申明式事務(wù) -->
<tx:annotation-driven transaction-manager="transactionManager"/>
問(wèn)題分析
其實(shí)這并不是我們事務(wù)配置的問(wèn)題素跺,而是我們定義<context:component-scan base-package="包路徑">
掃包規(guī)則的問(wèn)題二蓝,在spirngmvc配置文件中,我們掃描了所有的ben文件指厌,但是我們是使用spring進(jìn)行事務(wù)管理的刊愚。但是我們的spring-mybatis配置文件中并沒(méi)有配置掃包規(guī)則。
配置文件不同踩验,管理域也是不一樣的鸥诽,在springmvc配置了掃描所有bean文件,雖然其中包含了springmvc管理的箕憾,也包含了spring管理的牡借,但是我們的spring-mybatis文件中并沒(méi)有掃描和管理spring的配置,所以袭异,spring-mybatis配置文件并不能訪問(wèn)到springmvc中的spring管理钠龙。因此,即使配置了事務(wù)注解,也不會(huì)被spring管理碴里,從而造成了出錯(cuò)了也不會(huì)對(duì)事務(wù)進(jìn)行回滾沈矿。
問(wèn)題處理
修改方式,讓springmvc配置文件只掃描controller目錄并闲,并在spring-mybatis文件中细睡,添加掃描和管理spring的配置帝火。
修改后:
springmvc配置
<context:component-scan base-package="com.alex.controller">
spring-mybatis配置文件中添加
<context:component-scan base-package="com.alex.service">
因?yàn)槲覀兺ǔ6际窃趕ervice層進(jìn)行數(shù)據(jù)庫(kù)的操作和控制事務(wù),如果不是在service層進(jìn)行處理湃缎,只需要將package路徑修改到需要使用事務(wù)的包的路徑即可。
親測(cè)嗓违,重啟運(yùn)行后九巡,事務(wù)控制的方法中出錯(cuò)后蹂季,事務(wù)正趁峁悖回滾!
如果一個(gè)方法添加了事務(wù)控制偿洁,那么這個(gè)方法中的任何SQL操作撒汉,都不會(huì)立馬對(duì)數(shù)據(jù)庫(kù)的數(shù)據(jù)進(jìn)行修改,而是當(dāng)這個(gè)方法執(zhí)行結(jié)束之后涕滋,這些對(duì)數(shù)據(jù)庫(kù)修改的操作才會(huì)被提交睬辐。因此我們判斷事務(wù)是否生效宾肺,并不需要執(zhí)行到有錯(cuò)誤出現(xiàn)溯饵,只需要觀察事務(wù)控制方法內(nèi)的一個(gè)SQL執(zhí)行之后锨用,數(shù)據(jù)庫(kù)數(shù)據(jù)是否立馬發(fā)生了改變丰刊,改變了即說(shuō)明事務(wù)控制沒(méi)有生效,反之即表示事務(wù)控制生效了增拥!