宝哥软件园

Spring AOP部分解决了数据库读写分离的问题

编辑:宝哥软件园 来源:互联网 时间:2021-09-04

Spring AOP小节详解解决数据库读写分离的例子

为了减轻对数据库的压力,一般采用数据库的主/从模式,但这种模式会给应用带来一些麻烦,比如在读取数据时,如何将数据写入主库并从从库中读取。如果应用判断失误,将数据写入从库会对系统造成致命打击。

读写分离的解决方案有很多,其中常用的是SQL解析和数据源动态设置。Sql解析主要是分析插入/选择/更新/删除哪个SQL语句,从而对应选择主从。在动态设置数据源时,通过截取方法名称来确定主方法和从方法,例如,保存*(形式)、插入*(形式)的方法使用主库,以select()开头的方法使用从库。很多公司使用@Master、@Slave等自定义标签来选择主从,有的公司直接调用setxxMaster、setxxSlave等代码来选择主从。

主要介绍基于Spring AOP动态设置数据源的方法。注意,本文是基于你自己项目的实际情况,不是一个大概的方案,请知悉。

示意图

Spring AOP这一节的主要职责是截取Mybatis的Mapper接口,通过判断Mapper接口中的方法名称来确定主从。

弹簧AOP部分配置

AOP : config expose-proxy=' true ' AOP : pointcut id=' TxPointcut ' expression=' execution(* com . test.坚持.*.*(.))'/AOP : aspect ref=' readWriteInterceptor ' order=' 1 ' AOP : round pointcut-ref=' txPointcut ' method=' readowritedb '/AOP : aspect/AOP : config bean id=' readWriteInterceptor ' class=' com . test . readWriteInterceptor '属性名称=' readmethod list ' list value query */value value use */value get */value count */value find */value value list */value search *配置的节类是读写拦截器。这样,在调用Mapper接口的方法时,会先调用这个切片类的readOrWriteDB方法。这里要注意aop:aspect中order='1 '的配置,主要是解决刻面之间的优先级问题,因为整个系统中不太可能只有一个刻面类。

Spring AOP节类的实现

公共类读写拦截器{私有静态最终字符串DB _ SERVICE=' dbServiceprivate ListString ReadMethodList=new arrayListString();private ListString WriteMethodList=new arrayListString();public Object readOrWriteDB(proceedingjointpoint pjp)引发Throwable { String method name=pjp . getsignature()。getName();if(ischooseereaddb(method name)){//选择从属数据源} else if(ischooserwritedb(method name)){//选择主数据源} else {//选择主数据源} return pjp . progress();} private boolean isChooseWriteDB(String method name){ for(String mapped name : this . write method list){ if(IsMatch(method name,mapped name)){ return true;} }返回false} private boolean ischoosereddb(String method name){ for(String mapped name : this . readmethod list){ if(Ismatch(method name,mapped name)){ return true;} }返回false}私有布尔值isMatch(String methodName,String mappedName){ return patternMatchutils . SimpleMatch(Mappedname,method name);} public list string getReadMethodList(){ return readMethodList;} public void setReadMethodList(list string readMethodList){ this . readMethodList=readMethodList;} public list string getWriteMethodList(){ return writeMethodList;} public void setWriteMethodList(list string write methodlist){ this . write methodlist=write methodlist;}重写DynamicDataSource类中的getConnection方法

读写拦截器中的readOrWriteDB方法只决定是选择主还是从,为了得到正确的连接,我们必须重写数据源的getConnection方法。一般来说,一主多从,即一个主库和多个从库,需要解决多个从库之间的负载均衡、故障转移和重连失败等问题。

1.负载平衡问题。如果从机不多,系统并发读取不高,也可以用随机数直接访问。就是根据从机数量,然后生成随机数,随机访问从机。

2.故障转移,如果发现连接不可用,将其从从属列表中删除,然后在其回复后将其添加到从属列表中。

3.未能重新连接。第一次连接失败后,可以尝试几次,比如10次。

在业务方法中处理@事务注释

在这个项目中,大多数业务代码不需要交易,只有少数情况需要交易。根据上述方案,如果业务方法中的@Transactional标注没有经过特殊处理,那么在主从选择上会出现问题。众所周知,如果使用Spring事务,数据源的getConnection方法在同一个业务方法中只会被调用一次。如果映射器接口在这个业务方法中仅仅以select开始,那么将选择从库,并且当下一步调用以insert开始的映射器接口方法时,数据将被写入从库。如何解决这个问题?在输入标记有@Transactional注释的业务方法之前,必须指定主主库以供选择。您可以覆盖数据源转换管理器类中的doBegin方法,如下所示:

公共类MyTransactionManager extendsDataSourceTransactionManager { @ Override protected void dobe gin(对象事务,transactiondefinition definition){//选择主数据库super。dobegin(交易,定义);}}这样可以避免将数据写入从库的问题。

摘要

我的解决方案是基于实际项目,可能不适合你。我刚刚展示了解决方案。当然可以选择开源框架,比如阿里的Cobar,360的Atlas。

感谢您的阅读,希望对大家有所帮助,感谢您对本网站的支持!

更多资讯
游戏推荐
更多+