美文网首页
SSM项目配置多数据源

SSM项目配置多数据源

作者: felixfeijs | 来源:发表于2020-11-06 14:10 被阅读0次

    配置单数据源

    配置多数据源

    • 简介:该方案是基于注解、切面的方式实现SSM多数据源
    1. db.properties的配置
    jdbc.url.db1=jdbc:mysql://ip1:3306/db1?useUnicode=true&characterEncoding=utf-8 
    jdbc.username.db1=root 
    jdbc.password.db1=******
    
    jdbc.url.db2=jdbc:mysql://ip2:3306/db2?useUnicode=true&characterEncoding=utf-8 
    jdbc.username.db2=root 
    jdbc.password.db2=******
    
    1. applicationContext-db.xml的配置
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation=" 
              http://www.springframework.org/schema/beans 
              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
              http://www.springframework.org/schema/tx 
              http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
              http://www.springframework.org/schema/context 
              http://www.springframework.org/schema/context/spring-context-3.0.xsd 
              http://www.springframework.org/schema/aop 
              http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
              
        <!-- 加载数据源配置文件 -->
        <context:property-placeholder
            location="classpath:db.properties" />
    
        <bean name="dataSource1"
            class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
            destroy-method="close">
            <property name="url" value="${jdbc_url_db1}" />
            <property name="username" value="${jdbc_username_db1}" />
            <property name="password" value="${jdbc_password_db1}" />
            <!-- 初始化连接大小 -->
            <property name="initialSize" value="4" />
            <!-- 连接池最大使用连接数量 -->
            <property name="maxActive" value="400" />
            <!-- 连接池最小空闲 -->
            <property name="minIdle" value="4" />
            <!-- 获取连接最大等待时间 -->
            <property name="maxWait" value="5000" />
            <property name="validationQuery" value="${validationQuery}" />
            <property name="validationQueryTimeout" value="1" />
            <property name="testOnBorrow" value="false" />
            <property name="testOnReturn" value="false" />
            <property name="testWhileIdle" value="true" />
    
            <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
            <property name="timeBetweenEvictionRunsMillis" value="60000" />
            <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
            <property name="minEvictableIdleTimeMillis" value="300000" />
            <!-- 打开removeAbandoned功能 -->
            <property name="removeAbandoned" value="true" />
            <!-- 1800秒,也就是30分钟 -->
            <property name="removeAbandonedTimeout" value="1800" />
            <!-- 关闭<u>abanded</u>连接时输出错误日志 -->
            <property name="logAbandoned" value="true" />
            <!-- 监控数据库 -->
            <property name="filters" value="mergeStat" />
        </bean>
    
        <bean name="dataSource2"
            class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
            destroy-method="close">
            <property name="url" value="${jdbc_url_db2}" />
            <property name="username" value="${jdbc_username_db2}" />
            <property name="password" value="${jdbc_password_db2}" />
            <!-- 初始化连接大小 -->
            <property name="initialSize" value="4" />
            <!-- 连接池最大使用连接数量 -->
            <property name="maxActive" value="400" />
            <!-- 连接池最小空闲 -->
            <property name="minIdle" value="4" />
            <!-- 获取连接最大等待时间 -->
            <property name="maxWait" value="5000" />
            <property name="validationQuery" value="${validationQuery}" />
            <property name="validationQueryTimeout" value="1" />
            <property name="testOnBorrow" value="false" />
            <property name="testOnReturn" value="false" />
            <property name="testWhileIdle" value="true" />
            <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
            <property name="timeBetweenEvictionRunsMillis" value="60000" />
            <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
            <property name="minEvictableIdleTimeMillis" value="300000" />
            <!-- 打开removeAbandoned功能 -->
            <property name="removeAbandoned" value="true" />
            <!-- 1800秒,也就是30分钟 -->
            <property name="removeAbandonedTimeout" value="1800" />
            <!-- 关闭<u>abanded</u>连接时输出错误日志 -->
            <property name="logAbandoned" value="true" />
            <!-- 监控数据库 -->
            <property name="filters" value="mergeStat" />
        </bean>
    
        <bean id="dataSourceRouter"
            class="com.fei.demo.common.config.DataSourceRouter" lazy-init="true">
            <!-- 这里可以指定默认的数据源 -->
            <property name="defaultTargetDataSource" ref="dataSource1" />
            <property name="targetDataSources">
                <map key-type="java.lang.String">
                    <!-- 指对应的数据源 -->
                    <entry key="dataSource1" value-ref="dataSource1"></entry>
                    <entry key="dataSource2" value-ref="dataSource2"></entry>
                </map>
            </property>
        </bean>
    
        <!-- 配置MyBatis sqlsessionFactory -->
        <bean id="sqlsessionFactory"
            class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSourceRouter" />
            <!-- 引入MyBatis核心配置文件 -->
            <property name="configLocation" value="classpath:MyBatis.xml" />
            <!-- 引入Mapping配置文件 -->
            <property name="mapperLocations">
                <list>
                    <value>classpath:com/fei/demo/mapper/*.xml</value>
                </list>
            </property>
        </bean>
    
        <!-- 配置sqlSessionTemplate -->
        <bean id="sqlSessionTemplate" scope="prototype"
            class="org.mybatis.spring.SqlSessionTemplate">
            <constructor-arg index="0" ref="sqlsessionFactory" />
        </bean>
        
    </beans>
    
    
    1. 编写DataSourceRouter
    import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
    
    public class DataSourceRouter extends AbstractRoutingDataSource{
    
           @Override
           protected Object determineCurrentLookupKey() {
                  String dataSource = HandleDataSource.getDataSource();
                  return  dataSource;
           }
    }
    
    1. 编写HandleDataSource
    public class HandleDataSource {
    
           private static final ThreadLocal<String> holder = new 
    ThreadLocal<String>();
    
           public static void setDataSource(String datasource) {
                  holder.set(datasource);
           }
    
           public static String getDataSource() {
                  return holder.get();
           }
    
           public static void clearDataSource() {
                  holder.remove();
           }
    }
    
    1. 编写DataSource注解
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DataSource {
        
        String value();
    }
    
    1. 编写DataSourceAspect切面类
    import java.lang.reflect.Method;
    import java.text.MessageFormat;
    import org.aspectj.lang.JoinPoint;
    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.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    import com.fei.demo.common.annotation.DataSource;
    
    @Aspect
    @Component
    @Order(1)
    @EnableAspectJAutoProxy(proxyTargetClass=true)
    public class DataSourceAspect {
    
    static Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);
    
         // 拦截dao层的所有方法
         @Pointcut("execution(* com.fei.demo.*.dao..*.*(..))")
        public void aspect() {}
        
         @Before("aspect()")
        public void before(JoinPoint point) {
    
            Class<?> target = point.getTarget().getClass();
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method method = signature.getMethod() ;
            DataSource dataSource = null ;
            dataSource = this.getDataSource(target, method) ;
            if(dataSource == null){
                for (Class<?> clazz : target.getInterfaces()) {
                    dataSource = getDataSource(clazz, method);
                    if(dataSource != null){
                        break ;
                    }
                }
            }
            if(dataSource != null && !"".equals(dataSource.value()) ){
                HandleDataSource.setDataSource(dataSource.value());
            }
        }
           
        @After("aspect()")
        public void after(JoinPoint point) {
    
            HandleDataSource.setDataSource(null);
        }
    
           public DataSource getDataSource(Class<?> target, Method method){
           
            try {
                Class<?>[] types = method.getParameterTypes();
                Method m = target.getMethod(method.getName(), types);
                if (m != null && m.isAnnotationPresent(DataSource.class)) {
                    return m.getAnnotation(DataSource.class);
                }
                if (target.isAnnotationPresent(DataSource.class)) {
                    return target.getAnnotation(DataSource.class);
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(MessageFormat.format("通过注解切换数据源时发生异常[class={0},method={1}]:"
                        , target.getName(), method.getName()),e)  ;
            }
            return null ;
        }
    }
    
    
    1. Dao层使用DataSource注解,不加注解使用的是默认的数据源
    @Repository
    @Mapper
    @DataSource("dataSource2")
    public interface Test2Dao{
    
           testList();
    }
    
    
    @Repository
    @Mapper
    @DataSource("dataSource1")
    public interface Test1Dao{
    
           testList();
    }
    
    
    1. 至此SSM配置多数据源成功

    相关文章

      网友评论

          本文标题:SSM项目配置多数据源

          本文链接:https://www.haomeiwen.com/subject/zfetbktx.html