chengxiaohu159 2018-04-18 02:08 采纳率: 66.7%
浏览 1385
已采纳

SSH情况下如何做到多数据库切换

RT,数据库地址是动态的,如何才能从一个数据库切换到另一个数据库。数据库用的sqlserve。
另一个是动态数据库链接,不是写死的。
有没有可行性方案。

  • 写回答

3条回答 默认 最新

  • threenewbee 2018-04-18 02:13
    关注
     1.首先需要一个 数据源类型的类。
    
     public enum DBType {
          dataSource, frontDataSource;
    }
    
    2.需要一个本地线程变量对象保存 数据源类型,这里使用的 是ThreadLocal,因为ThreadLocal 可以为每个线程单独创立一个新的副本变量。
    public class ContextHolder {
        private static final ThreadLocal<Object> holder = new ThreadLocal<Object>();
    
        public static void setDbType(DBType dbType) {
            holder.set(dbType);
        }
    
        public static DBType getDbType() {
            return (DBType) holder.get();
        }
    
        public static void clearDbType() {
            holder.remove();
        }
    }
    
    3.需要一个动态数据源类用于代替之前的 dataSource bean,这个类需要继承AbstractRoutingDataSource,并且重写 determineCurrentLookupKey 方法,返回本地线程变量中保存的 数据源类型key。
    
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        @Override
        protected Object determineCurrentLookupKey() {
            DBType key = ContextHolder.getDbType();//获得当前数据源标识符
            System.out.println("当前数据源 :" + key);
            return key;
        }
    
    }
    
    4.需要一个拦截器,该拦截器可以根据实际情况进行配置,我这里是拦截 service根据方法名称去切换数据源,这里切记:
    
    a.@Order(1) 这个值必须有,因为数据源的获取也是通过拦截器中获取的,这个地方拦截器优先级必须高过数据源获取的拦截器。
    
    b.@Aspect  注解 需要在application.xml 配置启用
    
        <context:component-scan base-package="com">
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
        </context:component-scan>
        <!-- -开启 aspect 注解使用 -->
        <aop:aspectj-autoproxy />
    
    
    
    import java.lang.reflect.Method;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.Signature;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    /** 
     *  aop实现动态切换数据源 
     * 
     */  
    @Aspect  
    @Component 
    @Order(1)
    public class DataSourceAopProxy {  
    
        @Before("dataSourcePoint()")
        public  void setDataSource(JoinPoint joinPoint){  
    
            Signature signature = joinPoint.getSignature();  
            MethodSignature methodSignature = (MethodSignature) signature;  
            Method method = methodSignature.getMethod();  
    
            //此处进行切换数据源   根据业务条件   获取数据源id  
            if(method.getName().contains("Front")){
                 ContextHolder.setDbType(DBType.frontDataSource);
    
    
                 System.out.println("设置当前数据源 DBType.frontDataSource");
            }else{
                 ContextHolder.setDbType(DBType.dataSource);
    
                 System.out.println("设置当前数据源 DBType.dataSource");
            }
    
    
    
        }  
    
    
        @After("dataSourcePoint()")
        public  void after(JoinPoint joinPoint){  
    
            System.out.println("清除 DB type!");
            ContextHolder.clearDbType();
        }  
    
    
        //@Pointcut("execution(* com.dao.impl.*.*(..))")
        @Pointcut("execution(* com.service.impl.*.*(..))")
        private void dataSourcePoint(){  
    
        } 
    } 
    
    
    5.需要配置两个数据源和上面的数据源类型对应,我这里${jdbc.url}是读取的属性文件,你们可以在这里直接写值
    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
            <property name="driverClass" value="${jdbc.driver}" />
            <property name="jdbcUrl" value="${jdbc.url}" />
            <property name="user" value="${jdbc.username}" />
            <property name="password" value="${jdbc.password}" />
            <property name="initialPoolSize" value="${connection_pools.initial_pool_size}" />
            <property name="minPoolSize" value="${connection_pools.min_pool_size}" />
            <property name="maxPoolSize" value="${connection_pools.max_pool_size}" />
            <property name="maxIdleTime" value="${connection_pools.max_idle_time}" />
            <property name="acquireIncrement" value="${connection_pools.acquire_increment}" />
            <property name="checkoutTimeout" value="${connection_pools.checkout_timeout}" />
        </bean>
    
    
        <bean id="frontDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
            <property name="driverClass" value="${front.jdbc.driver}" />
            <property name="jdbcUrl" value="${front.jdbc.url}" />
            <property name="user" value="${front.jdbc.username}" />
            <property name="password" value="${front.jdbc.password}" />
            <property name="initialPoolSize" value="${connection_pools.initial_pool_size}" />
            <property name="minPoolSize" value="${connection_pools.min_pool_size}" />
            <property name="maxPoolSize" value="${connection_pools.max_pool_size}" />
            <property name="maxIdleTime" value="${connection_pools.max_idle_time}" />
            <property name="acquireIncrement" value="${connection_pools.acquire_increment}" />
            <property name="checkoutTimeout" value="${connection_pools.checkout_timeout}" />
        </bean>
    
    
    
    6.需要 修改 bean为entityManagerFactory的配置,其中将dataSource属性配置为 mysqlDynamicDataSource,如下:
    
        <property name="dataSource" ref="mysqlDynamicDataSource" />
    
    7.最后一步,配置 bean mysqlDynamicDataSource,对应上一步。
    
    a.此处bean中targetDataSources 为目标数据源,key-type 值为数据源类型类,也就是第一条那个枚举。
    
    b.map 中的key  对应的是数据源类型中的 两个枚举值,value-ref 则是第五条 配置的两个bean。
    
    c.defaultTargetDataSource 为默认的数据源类型,就是本地线程变量中值 为null而默认的数据源对象。   
    
         <bean id="mysqlDynamicDataSource" class="com.titanos.dynamic.DynamicDataSource">
            <property name="targetDataSources">
                <!-- 标识符类型 -->
                <map key-type="com.dynamic.DBType">
                    <entry key="dataSource" value-ref="dataSource"/>
                    <entry key="frontDataSource" value-ref="frontDataSource"/>
                </map>
            </property>
            <property name="defaultTargetDataSource" ref="dataSource"/>
        </bean>
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 关于logstash转发日志时发生的部分内容丢失问题
  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?