美文网首页
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