ssm 多数据源 注解版本

application.xml 配置如下

XML 复制代码
<!-- 使用 DruidDataSource 数据源 -->
 <bean id="primaryDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
 </bean>
<!-- 使用 数据源 1-->
 <bean id="logDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
 </bean>

 <!-- 配置动态加载数据源 -->
    <bean id="druidDynamicDataSource" class="com.iss.sso.utils.DynamicDataSource">
        <property name="defaultTargetDataSource" ref="primaryDataSource" />
        <property name="targetDataSources">
            <map>
                <entry key="primaryDataSource" value-ref="primaryDataSource"/>
                <entry key="scheduleDataSource" value-ref="logDataSource"/>
                
            </map>
        </property>
    </bean>
<!--3.配置SqlSessionFactory对象-->
 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <!--往下才是mybatis和spring真正整合的配置-->
        <!--注入数据库连接池-->
            <property name="dataSource" ref="druidDynamicDataSource"/>
        <!--
            配置mybatis全局配置文件:mybatis-config.xml
            指定Mybatis的配置文件位置。如果指定了该属性,
            那么会以该配置文件的内容作为配置信息构建对应的SqlSessionFactoryBuilder,
            但是后续属性指定的内容会覆盖该配置文件里面指定的对应内容
        -->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--
            扫描entity包,使用别名,多个用;隔开
            一般对应实体类所在的包,这个时候会自动取对应包中不包括包名的简单类名作为包括包名的别名。
            多个package之间可以用逗号或者分号等来进行分隔。(value的值一定要是包的全名)
        -->
        <property name="typeAliasesPackage" value="com.sso.**.domain"/>
        <!--
            扫描sql配置文件:mapper需要的xml文件
            Mapper文件存放的位置,当Mapper文件跟对应的Mapper接口处于同一位置的时候可以不用指定该属性的值
        -->
        <property name="mapperLocations" value="classpath:/mapper/*.xml"/>
     
    </bean>
-----     动态数据源
<bean id="dynamicDataSourceAspect" class="com.sso.utils.DynamicDataSourceAspect">
    </bean>
 <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--引入数据源-->
        <property name="dataSource" ref="druidDynamicDataSource"/>
    </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="update*" propagation="REQUIRED" isolation="DEFAULT"/>
            <tx:method name="del*" 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>
 <aop:config proxy-target-class="true">
        <aop:pointcut id="myPointcut" expression="execution(* com.sso.*.dao.*.*(..))"/>
        <aop:advisor advice-ref="dynamicDataSourceAspect" pointcut-ref="myPointcut" order="1"/>
        <!--把事务控制在Service层-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" order="2"/>
    </aop:config>

动态数据源 核心类

java 复制代码
/**
 * 动态数据源加载
 *
 * @author
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSource.class);

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

    @Override
    protected Object determineCurrentLookupKey() {
        logger.debug("===当前数据源: {}===", key.get());
        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();
    }

}

spring aop 植入

java 复制代码
@Aspect
@Order(-10)
@Component
public class DynamicDataSourceAspect implements MethodBeforeAdvice, AfterReturningAdvice {

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

    /**
     * 目标方法正常完成后被织入,关闭数据源
     *
     * @param o
     * @param method
     * @param objects
     * @param o1
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) {
        //这里做一个判断,有使用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)) {
        String clazzName = method.getDeclaringClass().getName();
        String methodName = method.getName();
            log.info("{}.{} 准备切换数据源", clazzName, methodName, DynamicDataSource.getDatasource());
            DataSourceAnnotation dataSourceAnnotation = method.getAnnotation(DataSourceAnnotation.class);
            DynamicDataSource.setDataSource(dataSourceAnnotation.value());
            log.info("{}.{} 数据源切换为:{}", clazzName, methodName, DynamicDataSource.getDatasource());
        } else {
            DynamicDataSource.setDataSource(DataSourceAnnotation.PRIMARY);
        }
    }
}
相关推荐
艾迪的技术之路10 分钟前
redisson使用lock导致死锁问题
java·后端·面试
今天背单词了吗98028 分钟前
算法学习笔记:8.Bellman-Ford 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
java·开发语言·后端·算法·最短路径问题
天天摸鱼的java工程师31 分钟前
使用 Spring Boot 整合高德地图实现路线规划功能
java·后端
东阳马生架构1 小时前
订单初版—2.生单链路中的技术问题说明文档
java
咖啡啡不加糖1 小时前
暴力破解漏洞与命令执行漏洞
java·后端·web安全
风象南1 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
DKPT1 小时前
Java享元模式实现方式与应用场景分析
java·笔记·学习·设计模式·享元模式
Percep_gan1 小时前
idea的使用小技巧,个人向
java·ide·intellij-idea
缘来是庄1 小时前
设计模式之迭代器模式
java·设计模式·迭代器模式