zoukankan      html  css  js  c++  java
  • ssm 在不同的数据库中进行切换(开启事物禁用)

    注意: ------引用

    1. AOP可以触发数据源字符串的切换
    2. 数据源真正切换的关键是 AbstractRoutingDataSource 的 determineCurrentLookupKey() **被调用,此方法是在open connection**时触发
    3. 事务是在connection层面管理的,启用事务后,一个事务内部的connection是复用的,所以就算AOP切了数据源字符串,但是数据源并不会被真正修改

    综上所述:
    如果要使用事务,还是别用determineCurrentLookupKey()这种方法切数据源了,得配置多个才行

    在ssm 运用的过程中,有时我们需要在不同数据库中进行切换

    进行数据的增删改查,此时我们需要运用spring 的aop 原理进行配置

    总体来说过程分三步,1 必要类的建立(放在最后,复制即可) 2 db.properties修改 3  spring-dao.xml 的配置

    2 db.properties修改

    #数据库1
    db.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
    db.url=jdbc:sqlserver://127.0.0.1:1433;databaseName=sj1
    db.user=js
    db.password=js
    
    #数据库2
    db.driver2=com.microsoft.sqlserver.jdbc.SQLServerDriver
    db.url2=jdbc:sqlserver://127.0.0.1:1433;databaseName=sj2
    db.user2=js
    db.password2=js

    3  spring-dao.xml 的配置

     <context:property-placeholder location="classpath:db.properties"/>
        <!--连接数据库1-->
        <bean id="datasource1" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${db.driver}"/>
            <property name="jdbcUrl" value="${db.url}"/>
            <property name="user" value="${db.user}"/>
            <property name="password" value="${db.password}"/>
            <!-- 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3-->
            <property name="initialPoolSize" value="3"/>
            <!--最大空闲时间,30秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0-->
            <property name="maxIdleTime" value="30"/>
            <!--连接池中保留的最大连接数。默认值: 15 -->
            <property name="maxPoolSize" value="100"/>
            <!-- 连接池中保留的最小连接数,默认为:3-->
            <property name="minPoolSize" value="10"/>
        </bean>
     <!--  &lt;!&ndash;连接数据库2-->
        <bean id="datasource2" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${db.driver}"/>
            <property name="jdbcUrl" value="${db.url2}"/>
            <property name="user" value="${db.user2}"/>
            <property name="password" value="${db.password2}"/>
          <!--  &lt;!&ndash; 初始化连接池中的连接数,取值应在minPoolSize与maxPoolSize之间,默认为3&ndash;&gt;-->
            <property name="initialPoolSize" value="3"/>
           <!-- &lt;!&ndash;最大空闲时间,30秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0&ndash;&gt;-->
            <property name="maxIdleTime" value="30"/>
           <!-- &lt;!&ndash;连接池中保留的最大连接数。默认值: 15 &ndash;&gt;-->
            <property name="maxPoolSize" value="100"/>
           <!-- &lt;!&ndash; 连接池中保留的最小连接数,默认为:3&ndash;&gt;-->
            <property name="minPoolSize" value="10"/>
        </bean>
    
       <!-- <&#45;&#45;;自定义数据源&ndash;&gt;-->
        <bean id="datasource" class="com.js.util.DynamicDataSource">//自己创建的类
            <!-- 默认使用sqlite数据库 1;-->
            <property name="defaultTargetDataSource" ref="datasource1"></property>
            <property name="targetDataSources">
                <map>
                    <entry key="dataSource1" value-ref="datasource1"></entry>
                    <entry key="dateSource2" value-ref="datasource2"></entry>
                </map>
            </property>
        </bean>
    
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="datasource"/>
            <property name="configLocation" value="classpath:mybatis/mybatis_config.xml"/>
            <property name="mapperLocations" value="classpath:com/js/*/dao/*.xml"/>
           
        </bean>
    
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.js.*.dao"/>
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        </bean>
    
    
        <!-- 切面 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
        <bean id="dataSourceAspect" class="com.js.util.DataSourceAspect">//自己创建的类
        </bean>
        <aop:config>
            <aop:aspect ref="dataSourceAspect">
                <!-- 拦截所有service方法,在dao层添加注解 -->
                <aop:pointcut expression="execution(* com.js..dao..*.*(..))" id="dataSourcePointcut"/>
                <aop:before method="intercept" pointcut-ref="dataSourcePointcut"/>
            </aop:aspect>
        </aop:config>

    运用:

    在dao 类上加(如果出问题了,你可以加在方法上试试)

    @DataSource("dataSource1") 或者  @DataSource("dataSource2")
    @Repository
    @DataSource("dataSource1")
    public interface JsDao{
    
    }

    1 必要类的建立(四个类哦)

    /**
     * @deprecated   数据库连接切换类
     *
     */
    
    @Target({ElementType.TYPE,ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DataSource{
        String value();
    }

    public class DataSourceAspect {
        //    拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
        public void intercept(JoinPoint point) throws Exception {
            Class<?> target = point.getTarget().getClass();
            MethodSignature signature = (MethodSignature) point.getSignature();
            // 默认使用目标类型的注解,如果没有则使用其实现接口的注解
    
            for (Class<?> clazz : target.getInterfaces()) {
                resolveDataSource(clazz, signature.getMethod());
            }
            resolveDataSource(target, signature.getMethod());
        }
    
        /**
         * 提取目标对象方法注解和类型注解中的数据源标识
         */
    
        public void resolveDataSource(Class<?> clazz, Method method) {
            try {
                Class<?>[] types = method.getParameterTypes();
    //            默认使用类型注解
                if (clazz.isAnnotationPresent(DataSource.class)) {
                    DataSource source = clazz.getAnnotation(DataSource.class);
                    DbContextHolder.setDataSource(source.value());
                }
    //            方法注解可以覆盖类型注解
                Method m = clazz.getMethod(method.getName(), types);
                if (m != null && m.isAnnotationPresent(DataSource.class)) {
                    DataSource source = m.getAnnotation(DataSource.class);
                    DbContextHolder.setDataSource(source.value());
                }
            } catch (Exception e) {
                System.out.println(clazz + ":" + e.getMessage());
            }
        }
    }

    /**
     *
     * 切换数据源的工具类
     */
    public class DbContextHolder {
        private static final ThreadLocal<String>THREAD_DATA_SOURCE =new ThreadLocal<>();
        /**
         * 设置当前数据库
         */
        public static void setDataSource(String dataSource) {
            THREAD_DATA_SOURCE.set(dataSource);
        }
        /**
         * 取得当前数据库
         */
        public static String getDataSource() {
            return THREAD_DATA_SOURCE.get();
        }
    
        /**
         * 清除上下文数据
         */
        public static void clearDataSource() {
            THREAD_DATA_SOURCE.remove();
        }
    }

    public class DynamicDataSource extends AbstractRoutingDataSource {
    
        @Override
        protected Object determineCurrentLookupKey() {
    
            return  DbContextHolder.getDataSource();
        }
    }
  • 相关阅读:
    安卓渗透测试环境搭建笔记
    spring boot Thymeleaf 模板注入 测试实践
    分析activity安全检测实践
    xposed的使用实践
    android组件安全测试实践
    Apache Dubbo Provider默认反序列漏洞复现实践(CVE-2020-1948)
    java设计模式--策略模式
    spring 发送email
    简单介绍
    有意义的礼物——英语小短文
  • 原文地址:https://www.cnblogs.com/jsbk/p/9843112.html
Copyright © 2011-2022 走看看