读写分离的好处:高并发互联网下减少数据库压力。详细请自行百度。
现在需求:读数据从test库中,写数据从test2中。根据调用方法的不同实现动态切换。
直接代码:
bean.xml:
dataSource1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
dataSource2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
dynamicDataSource" />
dynamicDataSource" />
/**
* 把当前请求的数据源(xml配置targetDataSources下的key)塞入到ThreadLocal中
*/
public class HandleDataSource {
public static final ThreadLocal holder=new ThreadLocal();
public static void putDataSource(String dataSource){
holder.set(dataSource);
}
/**
* ThreadLocal里面拿出当前请求的数据源
*/
public static String getDataSource(){
return holder.get();
}
public static void clearDataSource() {
holder.remove();
}
}
/**
* 数据源选择类:拿到动态切换的Key spring给你选择数据源
* @author Administrator
*
*/
public class DynamicDataSource extends AbstractRoutingDataSource{
/**
* 告诉spring使用哪个数据源
*/
@Override
protected Object determineCurrentLookupKey() {
return HandleDataSource.getDataSource();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TargetDataSource {
String value() default "";
}
@Service
public class ServiceImpl /*implements ServiceI*/ {
@Autowired
Dao dao;
/**
*方法执行前对数据源进行动态切换
* @return
*/
@TargetDataSource("test")
@Transactional(propagation=Propagation.REQUIRES_NEW)
public List findUser(){
List list= dao.findUser();
int a=10/0;
return list;
}
@TargetDataSource("test2")
@Transactional
public void addOrder(){
dao.addOrder();
/**
* 当前数据源事务调用另一个数据源事务时,设置事务的传播属性,否则会在一个数据源上添加事务,那就不对了。
*/
ServiceImpl service=(ServiceImpl)AopContext.currentProxy();
System.out.println(service.findUser());
}
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:cn/rjx/spring/mutidatasource1/bean.xml"}) //加载配置文件
@Component
public class Test01 {
Logger logger=LoggerFactory.getLogger(ServiceImpl.class);
@Resource
ServiceImpl serviceImpl;
@Test
public void test01(){
logger.info("#################################");
List list=serviceImpl.findUser();
System.out.println(list);
}
@Test
public void test02(){
logger.info("---------------------------------------");
serviceImpl.addOrder();
}
}
增强类:
@Aspect
@Order(-1)//多个aop配置时需要指定加载顺序(事务也是一个) -1为最先执行
@Component
//@EnableAspectJAutoProxy
public class DataSourceAspectJ /*implements MethodBeforeAdvice,AfterReturningAdvice*/ {
@Pointcut(value = "execution(* cn.rjx.spring.mutidatasource1.ServiceImpl.*(..))")
public void join(){
}
@Before("join()")
public void before(JoinPoint joinPoint){
System.out.println("before advice!");
//1.获取被代理类
Object target = joinPoint.getTarget();
//获取方法名称
String targetMethodName=joinPoint.getSignature().getName();
//2.拿到被代理类的接口
//Class>[] interfacezz=target.getClass().getInterfaces();
//3.拿到被代理的方法的入参
// Class>[] parameterTypes = ((MethodSignature)joinPoint.getSignature())
// .getMethod().getParameterTypes();
Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();
if(method.isAnnotationPresent(TargetDataSource.class)){
TargetDataSource annotation = method.getAnnotation(TargetDataSource.class);
HandleDataSource.putDataSource(annotation.value());
}else{
HandleDataSource.putDataSource("test");
}
//4. 获取接口方法上的注解
// for(Class> intfzz:interfacezz){
// try {
// Method method = intfzz.getMethod(targetMethodName, parameterTypes);
// if(method!=null){
// if(method.isAnnotationPresent(TargetDataSource.class)){
// TargetDataSource annotation = method.getAnnotation(TargetDataSource.class);
// HandleDataSource.putDataSource(annotation.value());
// }else{
// HandleDataSource.putDataSource("test");
// }
// }else{
// continue;
// }
//
// } catch (NoSuchMethodException e) {
// e.printStackTrace();
// } catch (SecurityException e) {
// e.printStackTrace();
// }
// }
}
@AfterReturning("join()")
public void after(){
System.out.println("after");
HandleDataSource.clearDataSource();
}
}
测试:执行test02()没异常情况下,往test2表中插入一条数据,并读取test中的的数据。如果有异常10/0事务回滚,两条操作都不执行。回滚指定事务段我没试,可以把我另一帖子的回滚段代码拿出来应该可以。
注意点:1.引入事务是切面那个order(-1)要加,表示位于增强链的最前。2.事务操作时要注意设置广播机制,尤其一个方法中调用另一个方法的事务时。
*************静态切换我研究研究,就是绑定sqlSessionFactory***************************
求助:能不能帮我把