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