首先,为何会碰到这样的问题?java
昨天写的一个业务上线了,可是在dev环境和test环境都能跑,可是到了线上环境发生数据不能插入的问题。
问了老大以后发现线上数据库是读写分离的,而后经过过滤器的才能进入写数据库卡,个人函数命名规范问题不符合过滤器的要求,致使从controller不能进入逻辑函数。面试
主要缘由:spring
AOP目标是把业务的共性问题提取出来集中放到一个统一的地方管理和控制。sql
不一样方法在java的完整周期(类加载期间,编译期,运行期间等)中不一样的时间段插入切面的方式不一样(即咱们想要他在这个时间完成的方法,这里建议先了解AOP的5种加强类型)。数据库
Cglib 是一个强大的,高性能的 Code 生成类库。
原理是在运行期间目标字节码加载后,经过字节码技术为一个类建立子类,
并在子类中采用方法拦截的技术拦截全部父类方法的调用,顺势织入横切逻辑。
因为是经过子类来代理父类,所以不能代理被 final 字段修饰的方法。
复制代码
在java编译期间有不一样的织入方法 编程
自动代理 基于注解的方式 或 xml方式 本项目是使用Spring+AspectJ:基于xml:aop:config的方式实现AOP织入。缓存
基于代理(jdk动态代理、cglib动态代理)实现的aop Spring aop使用了两种代理机制。一种是jdk动态代理,另外一种是cglib动态代理。 Jdk动态代理只支持接口代理,cglib支持类的代理。
下面这张退很好的总结了AOP的知识点。本人可能总结的不对,有问题请评论提醒。 安全
1.将读操做和写操做分离到不一样的数据库上,避免主服务器出现性能瓶颈;
2.主服务器进行写操做时,不影响查询应用服务器的查询性能,下降阻塞,提升并发;
3.数据拥有多个容灾副本,提升数据安全性。
4.同时当主服务器故障时,可当即切换到其余服务器,提升系统可用性;
复制代码
一、冷备份(定时全量/增量备份)
二、热备份(在主从架构上实现)
三、主从架构(N主M从)
四、读写分离(在主从架构上实现)
五、数据分片(分库分表(垂直分库 水平分表))
复制代码
参考:www.jianshu.com/p/b7834c990…springboot
一、Master将数据改变记录到二进制日志(binary log)中,也就是配置文件log-bin指定的文件,这些记录叫作二进制日志事件(binary log events)
二、Slave经过I/O线程读取Master中的binary log events并写入到它的中继日志(relay log)
三、Slave重作中继日志中的事件,把中继日志中的事件信息一条一条的在本地执行一次,完成数据在本地的存储,从而实现将改变反映到它本身的数据(数据重放)
复制代码
data数据源列表:master 写库 slave 读库
数据源DynamicDataSource类须要经过继承AbstractRoutingDataSource,class位于com.A.B.DynamicDataSource
<bean id="dynamicDataSource" class="com.A.B.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="master" value-ref="masterDataSource" />
<entry key="slave" value-ref="slaveDataSource" />
</map>
</property>
<property name="defaultTargetDataSource" ref="masterDataSource" />
</bean>
配置dataAOP 动态设置数据源,class位于com.T.A.dsadvice.DataSourceAdvice
<bean id="dataSourceAdvice" class="com.T.A.dsadvice.DataSourceAdvice" />
配置事务
<!-- spring aop manager transaction -->
<tx:advice id="txTransactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- add transaction -->
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="create*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="change*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="modify*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="edit*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="remove*" propagation="REQUIRED" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
经过配置aop:config实现AOP:AspectJ
<aop:config>
<aop:advisor advice-ref="dataSourceAdvice" pointcut="execution(* com.T.A.service..*Service.*(..))" order="1"/>
<aop:advisor advice-ref="txTransactionAdvice" pointcut="execution(* com.T.A.service..*Service.*(..)))" order="2" />
</aop:config>
复制代码
//determineCurrentLookupKey是重写的AbstractRoutingDataSource的方法
//主要是肯定当前应该使用哪一个数据源的key,由于AbstractRoutingDataSource 中保存的多个数据源是经过Map的方式保存的
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceSwitcher.getDataSource();
}
}
复制代码
public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice
复制代码
一共三个数据源:master slave 动态数据源 保存在master和slave,为了防止spring注入异常,因此master和slave都是主动实例化的,并非交给spring管理bash
MybatisConfiguration 主要是配置的sqlSessionFactory和sqlSessionTemplate,以及Mybatis的扩展框架Mapper的配置,若是不须要Mapper,能够不用配置scannerConfigurer
@Before是在方法执行前执行
@After在方法执行后执行
@Around环绕执行,能够再方法执行先后操做
@Aspect放在类名上面,把当前类标识为一个切面供容器读取
@Pointcut切入点,此注解放在方法上面,指向须要使用的切面编程的方法。此注解下面的方法并不会执行
复制代码
总结本项目中使用AOP实现主从分离的方式:
对于AOP来讲,最重要的点在于: