在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>
<!-- <!–連接配接資料庫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}"/>
<!-- <!– 初始化連接配接池中的連接配接數,取值應在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>
<!-- <--;自定義資料源–>-->
<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();
}
}