昨天写的一个业务上线了,但是在dev环境和test环境都能跑,但是到了线上环境发生 数据不能插入 的问题。
问了老大之后发现线上数据库是读写分离的,然后通过过滤器的才能进入写数据库卡,我的函数命名规范问题不符合过滤器的要求,导致从controller不能进入逻辑函数。
AOP目标是 把业务的共性问题 提取出来集中放到一个统一的地方管理和控制。
不同方法在java的完整周期(类加载期间,编译期,运行期间等)中 不同的时间段插入切面的方式不同 (即我们想要他在这个时间完成的方法,这里建议先了解 AOP的5种增强类型 )。
Cglib 是一个强大的,高性能的 Code 生成类库。 原理是在运行期间目标字节码加载后,通过字节码技术为一个类创建子类, 并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。 由于是通过子类来代理父类,因此不能代理被 final 字段修饰的方法。 复制代码
在java编译期间有不同的织入方法
对于AOP来说,最重要的点在于:
参考: juejin.im/post/5c0153…
1.将读操作和写操作分离到不同的数据库上,避免主服务器出现性能瓶颈; 2.主服务器进行写操作时,不影响查询应用服务器的查询性能,降低阻塞,提高并发; 3.数据拥有多个容灾副本,提高数据安全性。 4.同时当主服务器故障时,可立即切换到其他服务器,提高系统可用性; 复制代码
1、冷备份(定时全量/增量备份) 2、热备份(在主从架构上实现) 3、主从架构(N主M从) 4、读写分离(在主从架构上实现) 5、数据分片(分库分表(垂直分库 水平分表)) 复制代码
参考: www.jianshu.com/p/b7834c990…
1、Master将数据改变记录到二进制日志(binary log)中,也就是配置文件log-bin指定的文件,这些记录叫做二进制日志事件(binary log events) 2、Slave通过I/O线程读取Master中的binary log events并写入到它的中继日志(relay log) 3、Slave重做中继日志中的事件,把中继日志中的事件信息一条一条的在本地执行一次,完成数据在本地的存储,从而实现将改变反映到它自己的数据(数据重放) 复制代码
data所有数据源列表:master 写库 slave 读库
数据源DynamicDataSource类需要通过继承AbstractRoutingDataSource
<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="lingxu_masterDataSource" />
</bean>
配置dataAOP 动态设置数据源
<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: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 复制代码