SSM配置双数据源

一、最简单的配置方法

1、在datasource.properties文件配置数据源信息

jdbc.driverClassName = com.mysqL.jdbc.Driver
jdbc.urL = jdbc:mysqL://localhost:3306/one
jdbc.username = test1
jdbc.password = 123

jdbc.driverClassName2 = com.mysqL.jdbc.Driver
jdbc.urL2 = jdbc:mysqL://localhost:3307/one
jdbc.username2 = test2
jdbc.password2 = 123

2、SSM项目需要在XML里面进行相关配置

<!--第一个数据库-->
<bean id="One_dataSource" class= "org.apache.commons.dbcp.BasicDataSource" destroy -method="close">
<property name= "driverClassName" value=" ${jdbc.driverCLassName}" />
<property name="urL"  value="${jdbc.urL}" />
<property name="username"  value="${jdbc.username}" />
<property name="password"  value="${jdbc.password}" />
<property name= "maxActive"  value= "30"/>
<property name="maxIdle" value="20" />
<property name="maxWait" value="60000" />
</bean>

<!--第二个数据库-->
<bean id="Two_dataSource" class= "org.apache.common.dbcp.BasicDataSource" destroy -method="close">
<property name= "driverClassName" value=" ${jdbc.driverCLassName2}" />
<property name="urL" value="${jdbc.urL2}" />
<property name="username"  value="${jdbc.username2}" />
<property name="password"  value="${jdbc.password2}" />
<property name= "maxActive" value= "30"/>
<property name="maxIdle" value="20" />
<property name="maxWait" value="60000" />>
</bean>

3、对两个数据源进行相关配置

 <bean id="dataSourceAspect" class="com.javal.util.DataSwitchAop" />
    <aop:config>
        <aop:aspect ref="dataSourceAspect" >
            <!-- 拦截所有service方法 -->
            <!--我这里实在service上面加的注解,可自行调换  -->
            <aop:pointcut id="dataSourcePointcut" expression="execution(* com.javal.service..*.*(..))"/>
            <aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
        </aop:aspect>
    </aop:config>
    <!--启动对@AspectJ注解的支持 , proxy-target-class设置为true表示通知spring使用cglib而不是jdk的来生成代理方法,这样AOP可以拦截到Controller -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

<!--配置指定的类-->
<bean id="dataSource" class= "com.yjy.util.DynamicDataSource">
<property name ="targetDataSources">
<map key-type="java.Lang.String">
<--指定LookupKey和与之对应的数据源,这里的key可以自行定义,要切换数据库的时候以key为标识,不要写错- ->
<entry key= "One_dataSource"  value-ref= "One_dataSource "></entry>
<entry key= "Two_dataSource"  value-ref= "Two_dataSource "></ entry>
</map>
</property>
<--这里可以指定默认的数据源->
<property name= "defauttTargetDataSource" ref= "One_dataSource "></property>
</bean>

	<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.javal.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>

    <!-- sql会话模版 -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype">
        <constructor-arg ref="sqlSessionFactory"/>
    </bean>

	<!--事务控制-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

4、程序中调用需要的库

4.1 新建DynamicDataSource类

我们先要重写determineCurrentLookupKey方法,我们新建一个创建一个DynamicDataSource的类,用来获取自定义获取数据源的标识(和当前线程中使用的数据源):

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
 
public class DynamicDataSource extends AbstractRoutingDataSource {
    
    
 
    @Override
    protected Object determineCurrentLookupKey() {
    
    
        // 从自定义的位置获取数据源标识
        return DynamicDataSourceHolder.getDataSource();
    }
    
}

4.2 新建DynamicDataSourceHolder类

public class DynamicDataSourceHolder{
    
    

  private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal();
  
  public static String getDataSource(){
    
    
  
    return (String)THREAD_DATA_SOURCE.get();
    
  }
  
  public static void setDataSource(String dataSource){
    
    
  
    THREAD_DATA_SOURCE.set(dataSource);
    
  }
  
  public static void clearDataSource(){
    
    
  
    THREAD_DATA_SOURCE.remove();
    
  }
  
}

4.3 调用方法更换数据源

public void data() {
    
    

        JSONObject jsonObject = new JSONObject();
        List<Map<String ,Object>> list = testmapper.selectAllColor();
        jsonObject.put("AllColor",list);
        //切换数据源 
        DynamicDataSourceHolder.setDataSource( "Two_dataSource") ;
        testmapper.addAllColor();
    }

注意:因为配置了默认数据源,所以默认为第一个数据源,需要切换数据源的时候再进行切换。

建议:如果切换了数据源,需要在继续操作默认数据源的时候,建议切换回默认数据源。

二、注解方式

相关配置与简单方法大同小异,程序中调用的方法改成如下即可:

1、添加依赖

<dependency>
	<groupId>aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.5.2</version>
</dependency>

2、相关类

(1)自定义注解:DataSource (后面测试时切换数据源时使用)

import java.lang.annotation.*;
 
//设置注解
@Retention(RetentionPolicy.RUNTIME)
@Target({
    
    ElementType.METHOD, ElementType.TYPE})
@Documented
public @interface DataSource {
    
    
    String value() default "";
}

(2)DataSwitchAop类

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import com.zyl.crm.util.DynamicDataSourceHolder;
import java.lang.reflect.Method;
 
public class DataSwitchAop {
    
    
    /**
     * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
     */
 
    public void intercept(JoinPoint point) throws Exception {
    
    
        Class<?> target = point.getTarget().getClass();
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 默认使用目标类型的注解,如果没有则使用其实现接口的注解
        for (Class<?> clazz : target.getInterfaces()) {
    
    
            resolveDataSource(clazz, signature.getMethod());
        }
        resolveDataSource(target, signature.getMethod());
    }
    /**
     * 提取目标对象方法注解和类型注解中的数据源标识
     */
    private void resolveDataSource(Class<?> clazz, Method method) {
    
    
        try {
    
    
            Class<?>[] types = method.getParameterTypes();
            // 默认使用类型注解
            if (clazz.isAnnotationPresent(DataSource.class)) {
    
    
                DataSource source = clazz.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSource(source.value());
            }
            // 方法注解可以覆盖类型注解
            Method m = clazz.getMethod(method.getName(), types);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
    
    
                DataSource source = m.getAnnotation(DataSource.class);
                DynamicDataSourceHolder.setDataSource(source.value());
            }
        } catch (Exception e) {
    
    
            System.out.println(clazz + ":" + e.getMessage());
        }
    }
}

(3)DynamicDataSourceHolder 类

public class DynamicDataSourceHolder {
    
    
 
    private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();
 
    public static String getDataSource(){
    
    
 
        return dataSourceKey.get();
 
    }
 
    public static void setDataSource(String dataSource){
    
    
 
        dataSourceKey.set(dataSource);
 
    }
 
    public static void clearDataSource(){
    
    
 
        dataSourceKey.remove();
 
    }
 
}

(4)DynamicDataSource类

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.reactive.AbstractReactiveTransactionManager;
 
public class DynamicDataSource extends AbstractRoutingDataSource {
    
    
    @Override
    protected Object determineCurrentLookupKey() {
    
    
        return DynamicDataSourceHolder.getDataSource();
    }
}

3、测试

以下代码应该写在service中

@DataSource(value = "dataSourcetwo")
    public Nas tesx(Integer uid) {
    
    
        Nas nas1 = nasMapper.selectByPrimaryKey(uid);
        return nas1;
    }

@DataSource(value = “dataSourcetwo”)只要改变里面的value值即可,value值对应的是我们想找的数据源

猜你喜欢

转载自blog.csdn.net/LCHONSEONE/article/details/128881460