欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

解决spring mvc 多数据源切换,不支持事务控制的问题

程序员文章站 2024-02-27 13:33:15
一个项目中需要使用两个数据库,oracle 和mysql,于是参考各个blog,实现此功能。写好后才发现,原来的事务失效了,我去... spring-mybatis.xm...

一个项目中需要使用两个数据库,oracle 和mysql,于是参考各个blog,实现此功能。写好后才发现,原来的事务失效了,我去...

spring-mybatis.xml 配置

<bean id="configreader" class="org.springframework.beans.factory.config.preferencesplaceholderconfigurer">
  <property name="locations">
   <list>
    <value>classpath:spring/db.properties</value>
   </list>
  </property>
  <property name="ignoreresourcenotfound" value="true"/>
 </bean>

 <bean id="datasource" class="com.mchange.v2.c3p0.combopooleddatasource">
  <property name="driverclass" value="${jdbc.oracle.driverclassname}"></property>
  <property name="jdbcurl" value="${jdbc.oracle.url}"></property>
  <property name="user" value="${jdbc.oracle.username}"></property>
  <property name="password" value="${jdbc.oracle.userpassword}"></property>

  <property name="acquireincrement" value="5"></property>
  <property name="initialpoolsize" value="5"></property>
  <property name="maxidletime" value="60"></property>
  <property name="maxpoolsize" value="100"></property>
  <property name="minpoolsize" value="5"></property>
 </bean>


 <!-- 配置数据源:mysql start -->
 <bean name="mysqldatasource" class="com.alibaba.druid.pool.druiddatasource"
   init-method="init" destroy-method="close">
  <property name="driverclassname" value="${jdbc.mysql.driverclassname}"/>
  <property name="url" value="${jdbc.mysql.url}"/>
  <property name="username" value="${jdbc.mysql.username}"/>
  <property name="password" value="${jdbc.mysql.userpassword}"/>

  <!-- 初始化连接大小 -->
  <property name="initialsize" value="5"/>
  <!-- 连接池最大使用连接数量 -->
  <property name="maxactive" value="30"/>
  <!-- 连接池最小空闲 -->
  <property name="minidle" value="2"/>
  <!-- 获取连接最大等待时间 -->
  <property name="maxwait" value="300"/>

  <property name="validationquery" value="select 1"/>
  <property name="testonborrow" value="false"/>
  <property name="testonreturn" value="false"/>
  <property name="testwhileidle" value="true"/>

  <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
  <property name="timebetweenevictionrunsmillis" value="10000"/>
  <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
  <property name="minevictableidletimemillis" value="30000"/>

  <!-- 打开removeabandoned功能 -->
  <property name="removeabandoned" value="true"/>
  <!-- 1800秒,也就是30分钟 -->
  <property name="removeabandonedtimeout" value="1800"/>
  <!-- 关闭abanded连接时输出错误日志 -->
  <property name="logabandoned" value="true"/>

  <!-- 监控数据库 -->
  <property name="filters" value="stat"/>
 </bean>


 <bean id="multipledatasource" class="com.we.database.multipledatasource">
  <property name="defaulttargetdatasource" ref="datasource"/>
  <property name="targetdatasources">
   <map>
    <entry key="oracledatasource" value-ref="datasource"/>
    <entry key="mysqldatasource" value-ref="mysqldatasource"/>
   </map>
  </property>
 </bean>

 <!-- oracle mybatis file -->
 <bean id="sqlsessionfactory" class="org.mybatis.spring.sqlsessionfactorybean">
  <property name="datasource" ref="multipledatasource"/>
  <!--<property name="configlocation" value="classpath:configuration.xml" /> -->
  <property name="mapperlocations" value="classpath:com/we/dao/mapper/*.xml"/>
 </bean>

 <bean class="org.mybatis.spring.mapper.mapperscannerconfigurer">
  <property name="basepackage" value="com.we.dao"/>
  <property name="sqlsessionfactorybeanname" value="sqlsessionfactory"/>
 </bean>


 <!-- configure transaction -->
 <bean id="transactionmanager"
   class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
  <property name="datasource" ref="datasource"/>
 </bean>

 <!-- annotation transaction -->
 <tx:annotation-driven transaction-manager="transactionmanager" proxy-target-class="true"/>


 <!-- interception transatcion -->
 <tx:advice id="transactionadvice" transaction-manager="transactionmanager">
  <tx:attributes>
   <tx:method name="add*" propagation="required"/>
  </tx:attributes>
 </tx:advice>

 <!-- 配置数据库注解aop -->
 <bean id="datasourceaspect" class="com.we.database.datasourceaspect"/>

 <aop:config>
  <aop:pointcut id="transactionpointcut" expression="execution(* com.wewe.licai.service..*impl.*(..))"/>
  <aop:advisor pointcut-ref="transactionpointcut" advice-ref="transactionadvice" order="2"/>

  <!--数据源选择切面,保证在事务开始之前执行-->
  <aop:advisor pointcut-ref="transactionpointcut" advice-ref="datasourceaspect" order="1" />
 </aop:config>

注解切换,默认使用oracle数据源

@documented
@retention(retentionpolicy.runtime)
@target({elementtype.method,elementtype.type})

public @interface datasource {
  string name() default datasource.oracledatasource;
  string mysqldatasource = "mysqldatasource";
  string oracledatasource = "oracledatasource";
}

注解方式实现切换数据源,搜索注释,更换注释上面的数据源,支持类注释和方法注释

/**
 * created by eastday on 2017/9/21.
 */
public class datasourceaspect implements methodbeforeadvice,afterreturningadvice
{

 @override
 public void afterreturning(object returnvalue, method method,
        object[] args, object target) throws throwable {

  multipledatasource.cleardatasource();
 }

 @override
 public void before(method method, object[] args, object target)
   throws throwable {

  //首先取类上的数据源
  if(method.getdeclaringclass().isannotationpresent(datasource.class) && !method.isannotationpresent(datasource.class)) {

   datasource datasource = method.getdeclaringclass().getannotation(datasource.class);
   multipledatasource.setdatasource(datasource.name());

   //方法上的数据源 优先级高于类上的
  } else if (method.isannotationpresent(datasource.class)) {

   datasource datasource = method.getannotation(datasource.class);
   multipledatasource.setdatasource(datasource.name());
  }
  else
  {
   multipledatasource.setdatasource(datasource.oracledatasource);
  }
 }
}

继承abstractroutingdatasource实现数据源切换

public class multipledatasource extends abstractroutingdatasource {
 private static final threadlocal<string> datasources = new inheritablethreadlocal<string>();

 public static void setdatasource(string datasource) {
  datasources.set(datasource);
 }

 //清除数据源
 public static void cleardatasource() {
  datasources.remove();
 }

 @override
 protected object determinecurrentlookupkey() {
  return datasources.get();
 }
}

使用demo

@datasource(name = datasource.mysqldatasource)
public class contentserviceimpl implements icontentservice {

 @autowired
 private icontentdao contentdao;

 @override
 public content queryone(string type) {
  return contentdao.queryone(type);
 }
}

以上这篇解决spring mvc 多数据源切换,不支持事务控制的问题就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。