MyBatis配合spring事務處理註解無效的問題

yingxian_Fei發表於2017-04-26

在使用ssm中遇到使用了Spring的@Transactional註解加註了方法或service後,mybatis還是自動提交併且無法回滾的問題。在排查了程式碼的配置後發現,問題出現的原因主要是由於不同bean的配置位置造成的。

解決方法主要時調整bean宣告的位置,主要思路如下:

  (1)、資料庫相關的配置(datasource、service、dao、事物處理的管理類以及使用事務處理的方法)統一放到根ApplicationContext的配置中。
  (2)、web mvc相關的配置統一放到servlet的配置中。

本例資料庫部分使用xml進行配置,ApplicationContext和DispatcherServlet使用基於java的配置。大致部分的原始碼如下:

1、mybatis的xml配置

mybatis在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:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="  
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
	<!-- 自動掃描 -->
	<context:component-scan base-package="api.landsem.mybatis.service.impl" />
	<!-- 引入配置檔案 -->
	<bean id="propertyConfigurer"
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="classpath:jdbc.properties" />
	</bean>
	<!-- dataSource configuration -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
		destroy-method="close">
		<property name="jdbcUrl" value="${jdbc.url}" />
		<property name="driverClass" value="${jdbc.driverClassName}" />
		<property name="user" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
		<property name="minPoolSize" value="10" />
		<property name="maxPoolSize" value="100" />
		<property name="acquireIncrement" value="3" />
		<property name="maxIdleTime" value="60" />
		<property name="checkoutTimeout" value="18000" />
		<property name="idleConnectionTestPeriod" value="180" />
	</bean>
	<!-- spring和MyBatis完美整合,不需要mybatis的配置對映檔案 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<!-- 自動掃描mapping.xml檔案 -->
		<property name="mapperLocations" value="classpath:api/landsem/mybatis/mapping/*.xml" />
	</bean>

	<!-- DAO介面所在包名,Spring會自動查詢其下的類 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="api.landsem.mybatis.IDao" />
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
	</bean>
	<!-- transaction support -->
	<!-- PlatformTransactionMnager -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>
	<!-- enable transaction annotation support -->
	<tx:annotation-driven transaction-manager="transactionManager" /> 
</beans>

2、ApplicationContext配置

ApplicationContext的java配置類原始碼如下:

package api.landsem.base.configuration;

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.support.ResourceBundleMessageSource;

import api.landsem.device.v1.configuration.DeviceApiV1RootConfiguration;
import api.landsem.iot.v1.configuration.IotApiV1RootConfiguration;

@Configuration
@ComponentScan({"api.landsem.base.bean"})
@ImportResource("classpath:applicationContext-*.xml")
@Import({DeviceApiV1RootConfiguration.class,IotApiV1RootConfiguration.class})
public class RootConfiguration {

	@Bean("messageSource")
	public MessageSource getResourceBundleMessageSourc() {
		ResourceBundleMessageSource resource = new ResourceBundleMessageSource();
		resource.setBasename("i18n/i18n");
		return resource;
	}
}

3、DispatcherServlet配置

DispatcherServlet的java配置類原始碼如下:

package api.landsem.base.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import api.landsem.base.interceptor.LoggerInterceptor;
import api.landsem.device.v1.configuration.DeviceApiV1WebMvcConfiguration;
import api.landsem.iot.v1.configuration.IotApiV1WebMvcConfiguration;

@Configuration
@EnableWebMvc 
@Import({DeviceApiV1WebMvcConfiguration.class,IotApiV1WebMvcConfiguration.class})
public class DefaultWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter{
    @Bean  
    public ViewResolver viewResolver() {  
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();  
        resolver.setPrefix("/WEB-INF/views/");  
        resolver.setSuffix(".jsp");  
        return resolver;  
    }  
  
    @Override  
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {  
        configurer.enable();  
    }  
  
    @Override  
    public void addResourceHandlers(ResourceHandlerRegistry registry) {  
        super.addResourceHandlers(registry);  
        registry.addResourceHandler("/static/**","/css/**");      
    }

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		this.addLogInterceptors(registry);
		super.addInterceptors(registry);
	}  
	
	/** 
	* @Title: addLogInterceptors 
	* @Description: Add log interceptor to record request information. 
	* @param registry      
	*/  
	private void addLogInterceptors(InterceptorRegistry registry) {
		InterceptorRegistration reg = registry.addInterceptor(new LoggerInterceptor());
		if(null != reg)  {
			reg.addPathPatterns("/base/**","/wechat/**");
		}
	}
}


相關文章