spring mybatis 多数据源切换 事务添加

1、背景

最近项目里需要添加事务回滚处理,采用了spring多数据源,继承了AbstractRoutingDataSource来实现多数据源配置,之前其他人配置的事务不起作用(手动摊手),只能自己重新配置,记录下踩过的坑。目前只能在同一个数据源中进行回滚,暂不支持一个service层里面实现多个数据源回滚。

由于涉及到数据源切换,利用自定义注解,然后通过切面动态切换数据源,如下所示

1.1自定义注解

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value();
}

  

1.2 Dao持久层进行数据源切换

2、实现方式

 由于需要在service层实现事务处理,而事务处理必须在切换数据源之后,目前是在Dao层切换数据源,所以事务会失效。如果全部切换到service层进行数据源切换,修改的地方很多(无语啊),自己只能重新一个切面,并在service层切换数据源,代码及配置如下:

2.1 多数据源配置

<!--数据源-链接数据库的基本信息,这里直接写,不放到*.properties资源文件中 -->
    <context:property-placeholder location="classpath:application.properties"></context:property-placeholder>
	<bean id="dataSource1" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${ora1_jdbc.driver}" />
		<property name="url" value="${ora1_jdbc.url}" />
		<property name="username" value="${ora1_jdbc.username}"/>
		<property name="password" value="${ora1_jdbc.password}"/>
	</bean>
	
	<bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${ora2_jdbc.driver}" />
		<property name="url" value="${ora2_jdbc.url}" />
		<property name="username" value="${ora2_jdbc.username}"/>
		<property name="password" value="${ora2_jdbc.password}" />
	</bean>
	
	<bean id="dataSource" class="com.essbase.util.dbSourcesConfig.DynamicDataSource">
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<!-- 指定lookupKey和与之对应的数据源 -->
				<entry key="dataSource1" value-ref="dataSource1"></entry>
				<entry key="dataSource2" value-ref="dataSource2"></entry>
			</map>
		</property>
		<!-- 指定默认的数据源 -->
		<property name="defaultTargetDataSource" ref="dataSource1"></property>
	</bean>

2.2 aop配置

 1 <!-- 扫描包Service实现类 -->
 2     <context:component-scan base-package="com.essbase.service"></context:component-scan>
 3     <bean id="dataSourceAspect" class="com.essbase.util.dbSourcesConfig.DataSourceAspect"/>
 4     <bean id="dataSourceAopOnService" class="com.essbase.util.dbSourcesConfig.dataSourceAopOnService"/>
 5     <aop:config>
 6         <!--dao层切面-->
 7         <aop:pointcut expression="execution(* com.essbase.dao..*.*(..))" id="cut1"/>
 8         <!--service切面-->
 9         <aop:pointcut expression="execution(* com.essbase.service..*.*(..))" id="cut2"/>
10         <aop:advisor advice-ref="dataSourceAspect" pointcut-ref="cut1" order="0"/>
11         <aop:advisor advice-ref="dataSourceAopOnService" pointcut-ref="cut2" order="1"/>
12         <aop:advisor advice-ref="txAdvice" pointcut-ref="cut2" order="2" />
13     </aop:config>
14     <!--事务配置-->
15     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
16         <property name="dataSource" ref="dataSource" />
17     </bean>
18     <tx:advice id="txAdvice" transaction-manager="transactionManager"></tx:advice>

这里有两个切面,dataSourceAspect类是扫描dao层进行数据源切换,dataSourceAopOnService扫描service层,这里有一个坑,在扫描service层时,一直进不去切面类,经过排查原来是在spring.xml中没有扫描到service包(默认扫描本xml中的配置,写到其他xml中会导致扫描不到),添加<context:component-scan base-package="com.essbase.service"></context:component-scan>后正常。

 1 public class dataSourceAopOnService implements MethodBeforeAdvice, AfterReturningAdvice {
 2 
 3     @Override
 4     public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
 5         if(method.isAnnotationPresent(DataSource.class)) {
 6             DynamicDataSource.clearDataSource();
 7             System.out.println("**********************************service数据源已移除*************************************");
 8         }
 9     }
10 
11     @Override
12     public void before(Method method, Object[] objects, Object o) throws Throwable {
13         if(method.isAnnotationPresent(DataSource.class)){
14             DataSource dataSource = method.getAnnotation(DataSource.class);
15             DynamicDataSource.setDataSource(dataSource.value());
16             System.out.println("*******************************service数据源切换至:"+DynamicDataSource.getDatasource()+"**************************************");
17         }
18 
19     }
20 }

在这里要注意

<aop:advisor advice-ref="txAdvice" pointcut-ref="cut2" order="2" /> 事务切面的order值要小于数据源切面,order值越小权重越高

2.3 service层
1 //service层实现类
2 @Transactional()
3     public void test() {
4 
5 }
//service接口类
@DataSource("dataSource2")
  List<TbmFrdayEntity> test();

  通过以上配置就可以实现多数据源事务回滚(目前只能在同一个数据源中进行回滚,暂不支持一个service层里面实现多个数据源回滚)

猜你喜欢

转载自www.cnblogs.com/sunrj/p/10870857.html