SSM链接多个数据源
经过多日研究终于实验成功,以下是我在实验过程中的一些心得:
- 搭建简单的SSM框架并保证运行成功(自行百度)
- 配置多个数据源
- 编写切换数据源代码
- 注意点
配置多个数据源
在xml下配置数据源`
<bean id = "dataSource_first" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<!-- spring整合mybatis后,关于jdbc的配置在mybatis配置文件SqlMapConfig.xml中可以省略 -->
<property name="driverClass" value="${db.driver}"/>
<property name="jdbcUrl" value="${db.url}"/>
<property name="user" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<bean id="dataSource_second" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="driverClass" value="${db1.driver}"/>
<property name="jdbcUrl" value="${db1.url}" />
<property name="user" value="${db1.username}"/>
<property name="password" value="${db1.password}"/>
>
</bean>
<!-- 动态DataSource配置 -->
<bean id="dynamicDataSource" class="com.Source.util.DynamicDataSource">
<!--默认数据源 -->
<property name="defaultTargetDataSource" ref="dataSource_second"/>
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="dataSource_first" value-ref="dataSource_first"/>
<entry key="dataSource_second" value-ref="dataSource_second"/>
</map>
</property>
</bean>
<bean id = "sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
<!-- 指定MyBatis配置文件 -->
<property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"/>
</bean>
<bean id="dataSourceAspect" class="com.Source.util.DataSwitchAop" />
<aop:config>
<aop:aspect ref="dataSourceAspect" >
<!-- 拦截所有service方法 -->
<!--我这里实在controller上面加的注解,可自行调换 -->
<aop:pointcut id="dataSourcePointcut" expression="execution(* com.ssm.controller..*.*(..))"/>
<aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
</aop:aspect>
</aop:config>
<!--启动对@AspectJ注解的支持 , proxy-target-class设置为true表示通知spring使用cglib而不是jdk的来生成代理方法,这样AOP可以拦截到Controller -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
注意点
这个AOP标签决定了spring的jar包
原因是AOP代理方式有两种:一种是jdk的来生成代理方法,另一种是利用spring使用cglib来生成代理方法,两者代理区别是:jdk的代理面向的是接口代理,而cglib面对具体类代理,不能是接口。如果要在这两种代理方式中自由切换,只需将Spring的版本切换到了4.0.RELEASE 测试。
编写切换数据源代码
代码块
DynamicDataSource类:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
}
}
DynamicDataSourceHolder 类:
public class DynamicDataSourceHolder {
private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();
public static String getDataSource() {
return dataSourceKey.get();
}
public static void setDataSource(String dataSource) {
dataSourceKey.set(dataSource);
}
public static void clearDataSource() {
dataSourceKey.remove();
}
}
DataSource类:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//设置注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
public @interface DataSource {
String value() default "";
}
DataSwitchAop类:
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import com.njwangbo.util.DynamicDataSourceHolder;
public class DataSwitchAop {
/**
* 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
*
* @param point
* @throws Exception
*/
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());
}
/**
* 提取目标对象方法注解和类型注解中的数据源标识
*
* @param clazz
* @param method
*/
private void resolveDataSource(Class<?> clazz, Method method) {
try {
Class<?>[] types = method.getParameterTypes();
// 默认使用类型注解
if (clazz.isAnnotationPresent(DataSource.class)) {
DataSource source = clazz.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(source.value());
}
// 方法注解可以覆盖类型注解
Method m = clazz.getMethod(method.getName(), types);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource source = m.getAnnotation(DataSource.class);
DynamicDataSourceHolder.setDataSource(source.value());
}
} catch (Exception e) {
System.out.println(clazz + ":" + e.getMessage());
}
}
}
基本上该配置的都配置完了,该写的代码也都差不多了
测试
在controller里写这样一个类
import java.io.IOException;
import java.sql.Date;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class AllController {
@Autowired
private LService lService;
@RequestMapping("/getHotelMsg.action")
@DataSource(value="dataSource_first")
@ResponseBody
public List queryAll(HttpServletRequest request, HttpServletResponse response) throws IOException {
List list=null;
try{
list=lService.queryAll();
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
}
注意点:请在具体方法下添加@DataSource(value=”dataSource_first”),不要在整个类上面添加
心得
多百度,多尝试,细心点,耐心点,别放弃,希望能够对你的问题有所帮助。
来自多个博主的分享