专栏首页JavaWeb如何合理的使用动态数据源

如何合理的使用动态数据源

如何合理的使用动态数据源

        动态数据源在实现项目中用的是比较多的,比如在业务上做读写分离(主库负责写,从库负责读,主从同步可以直接使用mysql自带的),这里需要注意:写的时候要想保证事务就只能往一个数据源中写。

还有就是在做支付系统的时候,由于前几个月的订单记录客户是很少去查询的,在订单记录量比较大的时候(单表数据量大的情况下查询很慢)这个时候可以考虑将前几个月订单记录转移到新数据库中。

既然在实际项目中用的比较多,那就又学习的价值,接下来我们就一块去学习吧!少年

1.     要是还不知道如何搭建动态数据源可以参考我之前写的文章"基于自定义注解和Aop动态数据源配置"。

2.     完成动态数据源的搭建过后,我们就来分析一下在使用动态数据源会遇到的一些问题和一些注意事项。众所周知,Spring声明式事务是基于Aop实现的,动态数据源也是使用到Aop,这个时候我们应当先考虑多个Aop,它们是如何按排序执行?其实在Aop中,我们可以定义一个order属性,决定Aop的执行顺序,order越小越先执行,这个时候我们又应当考虑到底把哪个Aop放前面了?接下来我们就带着问题去测试一下呗,看看到底把哪个Aop放前面比较合适。

先将动态数据源Aop设置order=1,再将Spring事务Aop设置order=2(注意这里的配置和"基于自定义注解和Aop动态数据源配置"配置方式不是同一种,配置方式请参考文章:"Spring 声明式事务常用的二种配置方式 ")。

@Aspect
@Order(1)
@Component
public class DataSourceAspect {

	private static final Logger LOG = new Logger(DataSourceAspect.class);

	@Before("@annotation(ds)")
	public void changeDataSource(JoinPoint point, DataSource ds) throws Throwable {
		DynamicDataSourceHolder.setDataSourceType(ds.value().name());
	}
		
	@After("@annotation(ds)")
	public void restoreDataSource(JoinPoint point, DataSource ds) {
		DynamicDataSourceHolder.clearDataSourceType();

	}
}
<!-- 开启事务控制的注解支持 -->
<tx:annotation-driven transaction-manager="transactionManager" order="2"/>

测试代码如下:

@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
@DataSource(value = DataSourceType.SLAVE)
public void annotationNestedTransaction01(){
	SecurityAddition record = new SecurityAddition();
	record.setAmt(new Double(20));
	record.setCard(System.currentTimeMillis()+"");
	record.setOrder_no("Order-"+System.currentTimeMillis());
	record.setName("张三");
	securityAdditionMapper.insert(record);
}

日志对应如下:

认真分析日志我们能发现数据源的Aop是执行在事务Aop之前的,项目默认的数据源是Master,而上面代码重新设置了数据源为Slave,所以这个时候,下面事务Aop是在数据源为Slave下创建的事务,所以记录肯定是存在Slave表中的,那现在我们把Aop的执行顺序发过来看看实际的效果。

修改order顺序:

@Aspect
@Order(2)
@Component
public class DataSourceAspect {

	private static final Logger LOG = new Logger(DataSourceAspect.class);

	@Before("@annotation(ds)")
	public void changeDataSource(JoinPoint point, DataSource ds) throws Throwable {
		DynamicDataSourceHolder.setDataSourceType(ds.value().name());
	}
		
	@After("@annotation(ds)")
	public void restoreDataSource(JoinPoint point, DataSource ds) {
		DynamicDataSourceHolder.clearDataSourceType();

	}
}
<!-- 开启事务控制的注解支持 -->
<tx:annotation-driven transaction-manager="transactionManager" order="1"/>

这个时候测试代码不变,日志如下:

这个时候可以根据日志可以得出,事务Aop是执行在数据源Aop之前的,这个时候就不会达到切换数据源到Slave下目的,因为这个插入操作是在spring事务开启之后才去切换的,没有任何效果,这个时候在到Slave中操作新插入的记录是找不到的,事务aop会走默认的Master,可以得知在master中会有一条新记录。

总结:如何要在一个service方法中既要切换数据源又要保证这个方法的事务,这个时候我们就必须将数据源切换Aop放在事务Aop之前执行,还有就是千万要记住,如何在一个service方法上已经使用了spring的事务,就不要指望在方法中还去切换数据源了,如下面错误演示代码:

@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
@DataSource(value = DataSourceType.SLAVE)
public void annotationNestedTransaction01(){
	SecurityAddition record = new SecurityAddition();
	record.setAmt(new Double(20));
	record.setCard(System.currentTimeMillis()+"");
	record.setOrder_no("Order-"+System.currentTimeMillis());
	record.setName("张三");
	securityAdditionMapper.insert(record);
	
	Admin admin = new Admin();
	admin.setCreateTime(new Date());
	admin.setId(102);
	admin.setDoctorId(101);
	admin.setHospitalId(101);
	admin.setPassword("123456");
	admin.setPayName("张三");
	admin.setState(1);
	admin.setToken("88888888");
	admin.setAccount("zhangsan");
	admin.setType("USER");
	DynamicDataSourceHolder.setDataSourceType(DataSourceType.MASTER.name());  //手动切换数据到master
	adminMapper.insert(admin);
	DynamicDataSourceHolder.clearDataSourceType();
}

如上错误代码不会将admin插入到Master中,而是插入到Slave中了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JVM-一图让你全局了解JVM 原

    (adsbygoogle = window.adsbygoogle || []).push({});

    秋日芒草
  • 资源-demo

    (adsbygoogle = window.adsbygoogle || []).push({});

    秋日芒草
  • 基于自定义注解和Aop动态数据源配置

    秋日芒草
  • Java直接内存与非直接内存性能测试

    什么是直接内存与非直接内存 根据官方文档的描述: A byte buffer is either direct or non-direct. Given a d...

    用户1154259
  • Java的内存模型

      java的后端服务器开发中"高效并发"是我们经常会碰到的,而要写出高效的代码需要更多的积累与实践。而一些基础的内容是往这个方向发展的基石。所以我们就来介绍下...

    用户4919348
  • JAVA 内存模型 (Java Memory Model,JMM)

    是在硬件内存模型基础上更高层的抽象,它屏蔽了各种硬件和操作系统对内存访问的差异性,从而实现让Java程序在各种平台下都能达到一致的并发效果。

    微风-- 轻许--
  • 《深入理解java虚拟机-高效并发》读书笔记

    Java内存模型与线程 概述   多任务处理在现代计算机操作系统中几乎已是一项必备的功能,多任务运行是压榨手段,就如windows一样,我们使劲的压榨它运行多个...

    Java高级架构
  • 聊聊spring cloud的AbstractLoadBalancingClient

    本文主要研究一下spring cloud的AbstractLoadBalancingClient

    codecraft
  • JVM学习笔记——java内存模型与线程(1)

    多任务处理出现的重要原因是计算机的运算速度与存储及通信子系统的速度差距太大,大量的时间花费在磁盘I/O,数据库访问或者数据库访问上。除了充分利用计算机处理器的能...

    用户1665735
  • 0Day技术分析-4-堆溢出原理

    《0Day技术分析》系列文章已经全部推送完毕,需要的电子稿的请加QQ1041218129(备注好需求),也可以直接在公众号查看文章目录。 堆溢出原理 1 堆的工...

    zhisheng

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动