SSM项目配置多数据源

近期项目中需要对接其他系统,涉及到多个数据源的配置,在这里记录一下,方便以后自己查阅。

使用的数据库是sqlserver,步骤如下:

一、修改db.properties中的配置信息

jdbc.url=jdbc:sqlserver://localhost:1433;DatabaseName=test1
jdbc.username=3oJ82PFqtGI=
jdbc.password=yq3r3NucCgywOy7FXoydpg==

jdbc.urlsecend=jdbc:sqlserver://localhost:1433;DatabaseName=test2
jdbc.usernamesecend=3oJ82PFqtGI=
jdbc.passwordsecend=yq3r3NucCgywOy7FXoydpg==

        我这里的数据库连接信息做了加密,不加密也没有影响。

二、创建@DataSourceAnnotation 注解使用于aop进行数据源的切换

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceAnnotation {

    String value();

    String primary = "primary";

    String secend= "secend";

}

三、创建动态数据源DynamicDataSource继承AbstractRoutingDataSource

public class DynamicDataSource extends AbstractRoutingDataSource {

    /**
     * 数据源标识,保存在线程变量中,避免多线程操作数据源时互相干扰
     */
    private static final ThreadLocal<String> key = new ThreadLocal<String>();

    @Override
    protected Object determineCurrentLookupKey() {
        return key.get();
    }

    /**
     * 设置数据源
     *
     * @param dataSource 数据源名称
     */
    public static void setDataSource(String dataSource) {
        key.set(dataSource);
    }

    /**
     * 获取数据源
     *
     * @return
     */
    public static String getDatasource() {
        return key.get();
    }

    /**
     * 清除数据源
     */
    public static void clearDataSource() {
        key.remove();
    }

}

四、创建一个aop切面作用于目标方法上

@Component
public class DynamicDataSourceAspect implements MethodBeforeAdvice, AfterReturningAdvice {

    Logger log = LoggerFactory.getLogger("切换数据源");

    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        //这里做一个判断,有使用DataSourceAnnotation注解时才关闭数据源,有一个主要的数据源,就没有必要每次都去关闭
        if (method.isAnnotationPresent(DataSourceAnnotation.class)) {
            DynamicDataSource.clearDataSource();
            log.debug("数据源已关闭");
        }
    }

    /**
     * 拦截目标方法,获取由@DataSourceAnnotation指定的数据源标识,设置到线程存储中以便切换数据源
     */
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        if (method.isAnnotationPresent(DataSourceAnnotation.class)) {
            DataSourceAnnotation dataSourceAnnotation = method.getAnnotation(DataSourceAnnotation.class);
            DynamicDataSource.setDataSource(dataSourceAnnotation.value());
            log.debug("数据源切换为:" + DynamicDataSource.getDatasource());
        }
    }
}

五、配置动态数据源,将数据源交由sqlsessionfactory去处理

 <bean id="dataSourcePrimary" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close">
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <...其他配置,不一一列举>
 </bean>

 <bean id="dataSourceSecend" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close">
        <property name="url" value="${jdbc.urlsecend}"></property>
        <property name="username" value="${jdbc.usernamesecend}"></property>
        <property name="password" value="${jdbc.passwordsecend}"></property>
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <...其他配置,不一一列举>
  </bean>

  <!-- 动态数据源配置 -->
  <bean id="dataSource" class="com.test.config.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="primary" value-ref="dataSourcePrimary"></entry>
                <entry key="secend" value-ref="dataSourceSecend"></entry>
            </map>
        </property>
        <!-- 配置默认数据源 -->
        <property name="defaultTargetDataSource" ref="dataSourcePrimary"></property>
  </bean>

六、配置aop

 <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--引入数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="dynamicDataSourceAspect" class="com.test.config.DynamicDataSourceAspect">
    </bean>

    <!-- 开启事务注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!--定义事务增强,并制定事务管理器  -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--设置传播行为-->
            <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT"/>  
            <tx:method name="select*" propagation="SUPPORTS" isolation="DEFAULT" read-only="true"/>  
            <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>
    <!--设置切面  com.test.service.*.impl.*()-->
    <aop:config proxy-target-class="true">
        <aop:pointcut id="myPointcut" expression="execution(* com.test.service.*.impl.*.*(..))"/>
        <aop:advisor advice-ref="dynamicDataSourceAspect" pointcut-ref="myPointcut" order="1"/>
        <!--把事务控制在Service层-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" order="2"/>
    </aop:config>

这里需要注意的是order值越小,优先级越高,所以切换数据源order的值要比事务切面的值小,否则会出现数据源切换失败!

七、在需要切换为非默认数据的方法上加@DataSourceAnnotation(DataSourceAnnotation.secend)就可以完成数据源的切换了。

    @DataSourceAnnotation(DataSourceAnnotation.secend)
    @Override
    public List<User> listUser() {
        List<User> listUser = userMapper.selectListUser();
        return listUser;
    }

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值