天天看點

ssm 在不同的資料庫中進行切換

在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();
    }
}