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="dynamicDataSourceAop" class="com.essbase.util.dbSourcesConfig.DynamicDataSourceAop"/>
 4     <aop:config>
 5         <aop:pointcut expression="execution(* com.essbase.dao..*.*(..))||execution(* com.essbase.service..*.*(..))" id="cut1"/>
 6         <!--事务切面-->
 7         <aop:pointcut expression="execution(* com.essbase.service..*.*(..))" id="cut2"/>
 8         <aop:advisor advice-ref="dynamicDataSourceAop" pointcut-ref="cut1" order="1"/>
 9         <aop:advisor advice-ref="txAdvice" pointcut-ref="cut2" order="2" />
10     </aop:config>
11     <!--事务配置-->
12     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
13         <property name="dataSource" ref="dataSource" />
14     </bean>
15     <tx:advice id="txAdvice" transaction-manager="transactionManager"></tx:advice>

 

DynamicDataSourceAop类是扫描dao层和service层进行数据源切换,这里有一个坑,在扫描service层时,一直进不去切面类,经过排查原来是在spring.xml中没有扫描到service包(默认扫描本xml中的配置,写到其他xml中会导致扫描不到),
添加<context:component-scan base-package="com.essbase.service"></context:component-scan>后正常。
 1 public class DynamicDataSourceAop 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("**********************************数据源已移除*************************************");
 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("*******************************数据源切换至:"+DynamicDataSource.getDatasource()+"**************************************");
17         }
18 
19     }
20 }
 1 public class DynamicDataSource extends AbstractRoutingDataSource{
 2     /**
 3      * 数据源标识,保存在线程变量中,避免多线程操作数据源时互相干扰
 4      */
 5     private static final ThreadLocal<String> key = new ThreadLocal<String>();
 6 
 7     @Override
 8     protected Object determineCurrentLookupKey() {
 9          // 从自定义的位置获取数据源标识
10         return key.get();
11     }
12     /**
13      * 设置数据源
14      * @param dataSource 数据源名称
15      */
16     public static void setDataSource(String dataSource){
17         key.set(dataSource);
18     }
19     /**
20      * 获取数据源
21      * @return
22      */
23     public static String getDatasource() {
24         return key.get();
25     }
26 
27     /**
28      * 清除数据源
29      */
30     public static void clearDataSource(){
31         key.remove();
32     }
33 }

在这里要注意

<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层里面实现多个数据源回滚)

 

转载于:https://www.cnblogs.com/sunrj/p/10870857.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值