Spring学习总结(16)——Spring AOP实现执行数据库操作前根据业务来动态切换数据源
深刻讨论为什么要读写分离?
为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的。「读写分离」并不是多么神奇的东西,也带不来多么大的性能提升,也许更多的作用的就是数据安全的备份吧。
从一个库到读写分离,从理论上对服务器压力来说是会带来一倍的性能提升,但你仔细思考一下,你的应用服务器真的很需要这一倍的提升么?那倒不如你去试着在服务器使用一下缓存系统,如
Memcached、Redis 这些分布式缓存,那性能可能是几十倍的提升。而且,在服务器硬件异常强悍及性能廉价的今天,完全更没必要了,所以,在今天,我认为它更多的职责就是为了数据安全而设计的,同时又提升了一些性能,这样也挺好。
可能我们更应该称之为 主从分离 。
利用 AOP 实现读写分离
读写分离方式很简单,就是在你读数据是去连接 从库 ,在你写数据的时候去连接 主库 ,具体代码实现当然就是连接时候去操作了,这没什么难度,在代码里写就是了。可是,有追求的程序猿都是不是这么解决问题的呢!
我们知道 AOP 可以实现在方法开始执行前后插入执行我们想要的代码,那这样,我们是不是可以在 执行数据库操作前根据业务来动态切换数据源 呢?
思考一下这个方式理论上好像是可行的,这种方式首先不需要在业务代码中去做切换,二是可能以后我们不需要读写分离了,把 AOP 切换的代码去掉就行了,三是可能就是拓展性好了。
等不了了,开始撸代码
你可能想深入的了解的话,我这里给你几个程序里用到的关键字 enum(枚举) 、 annotation(自定义注解) 、 JoinPoint(注入点) 、 AbstractRoutingDataSource(数据源接口子类)
,你理解了这些就知道了,其实你并不需要深入某些深层的东西,了解下即可。
一、建立 JdbcContextHolder.java 类
public class JdbcContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setJdbcType(String jdbcType) {
contextHolder.set(jdbcType);
}
public static void setSlave() {
setJdbcType("slave");
}
public static void setMaster() {
clearJdbcType();
}
public static String getJdbcType() {
return (String) contextHolder.get();
}
public static void clearJdbcType() {
contextHolder.remove();
}
}
这个类的作用就是用来 设置、获取数据源连接
二、新建 DynamicDataSource.java 类,继承于 AbstractRoutingDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import cn.mayongfa.common.JdbcContextHolder;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
// 获取当前数据源连接
return JdbcContextHolder.getJdbcType();
}
}
通过研究,我们知道 determineCurrentLookupKey 方法是获取相关数据源连接的,所以重写 determineCurrentLookupKey
方法就可以啦,然后我们去通过刚刚我们建立的 JdbcContextHolder 类去获取。那怎么设置呢?
三、建立数据源 DataSourceType.java 枚举类
public enum DataSourceType {
//主库
Master("master"),
//从库
Slave("slave");
private DataSourceType(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这个枚举类的作用其实就是为了设置数据源而生的,它的目的就是让设置数据源时更方便,如丝般顺滑。
四、新建 DataSource.java Annotation(自定义注解)类
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DataSource {
DataSourceType value() default DataSourceType.Master;
}
自定义注解的意义不再过多讨论,一句话来说就是可以让你 在类或方法名上以打标签的形式让该方法变得不一样 。具体怎么「不一样」,这个在于你。
五、新建 DataSourceChoose.java 数据库切换类
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import cn.mayongfa.common.JdbcContextHolder;
public class DataSourceChoose {
//方法执行前
public void before(JoinPoint point){
Object target = point.getTarget();
String method = point.getSignature().getName();
Class<?>[] classz = target.getClass().getInterfaces();
MethodSignature methodSignature = (MethodSignature)point.getSignature();
Class<?>[] parameterTypes = methodSignature.getMethod().getParameterTypes();
try {
Method m = classz[0].getMethod(method, parameterTypes);
if (m!=null && m.isAnnotationPresent(DataSource.class)) {
DataSource data = m.getAnnotation(DataSource.class);
JdbcContextHolder.clearJdbcType();
JdbcContextHolder.setJdbcType(data.value().getName());
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
这个其实是一个拦截器类,主要作用就是拦截那些方法名上有 @DataSource 这个自定义注解的,完了根据获取注解的 value() 值,来做相应的数据源切换。
Spring学习总结(16)——Spring AOP实现执行数据库操作前根据业务来动态切换数据源的更多相关文章
- AOP获取方法注解实现动态切换数据源
AOP获取方法注解实现动态切换数据源(以下方式尚未经过测试,仅提供思路) ------ 自定义一个用于切换数据源的注解: package com.xxx.annotation; import org. ...
- Spring学习1:Spring基本特性
http://longliqiang88.github.io/2015/08/14/Spring%E5%AD%A6%E4%B9%A01%EF%BC%9ASpring%E5%9F%BA%E6%9C%AC ...
- [Spring学习笔记 6 ] Spring JDBC 详解
项目使用maven管理,pom.xml和项目组织如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xs ...
- Spring+Mybatis动态切换数据源
功能需求是公司要做一个大的运营平台: 1.运营平台有自身的数据库,维护用户.角色.菜单.部分以及权限等基本功能. 2.运营平台还需要提供其他不同服务(服务A,服务B)的后台运营,服务A.服务B的数据库 ...
- Spring Boot 如何动态切换数据源
本章是一个完整的 Spring Boot 动态数据源切换示例,例如主数据库使用 lionsea 从数据库 lionsea_slave1.lionsea_slave2.只需要在对应的代码上使用 Data ...
- Spring + Mybatis 项目实现动态切换数据源
项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库. 最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法. ...
- Spring动态切换数据源及事务
前段时间花了几天来解决公司框架ssm上事务问题.如果不动态切换数据源话,直接使用spring的事务配置,是完全没有问题的.由于框架用于各个项目的快速搭建,少去配置各个数据源配置xml文件等.采用了动态 ...
- 【转】MyBatis学习总结(二)——使用MyBatis对表执行CRUD操作
[转]MyBatis学习总结(二)——使用MyBatis对表执行CRUD操作 上一篇博文MyBatis学习总结(一)——MyBatis快速入门中我们讲了如何使用Mybatis查询users表中的数据, ...
- 在使用 Spring Boot 和 MyBatis 动态切换数据源时遇到的问题以及解决方法
相关项目地址:https://github.com/helloworlde/SpringBoot-DynamicDataSource 1. org.apache.ibatis.binding.Bind ...
随机推荐
- win server 2008 r2 iis+php 500错误内部服务器错误。
今天遇到一个错误是iis 500错误,由于server是别人负责的.查看日志没什么异常,就发如今任务日志里发现有一段时间间隔没有记录.一開始不知道为什么.之后日志里就都是500错误了,在iis哪里配置 ...
- Android SQLite服务--创建、增删改查
<pre name="code" class="java">import android.content.Context; import andro ...
- git的经常使用命令
$ git config --global user.name "姓名" $ git config --global user.email "xxx@qq.com&quo ...
- PyCharm 运行工程
- 【cl】子查询应用场景
有推荐人/没有推荐人的 recommender_id is null / is not null 谁是推荐人=他的id是别人的recommender_id=某个人的recommender_id是他的i ...
- 使用register_chrdev注册字符设备
1.2.2 使用register_chrdev注册字符设备 注册字符设备可以使用register_chrdev函数. int register_chrdev (unsigned int major, ...
- [BZOJ 3363] Cow Marathon
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=3363 [算法] 树的直径 [代码] #include<bits/stdc++. ...
- Spring版本功能变更&Spring4.x的新特性
有朋友想知道Spring不同版本都有哪些功能变更,说直接在百度搜索找到的结果都不是想要的,其实还是关键词不对,找Spring不同版本的新特性就能获得更好的结果.其实在Spring工程github的wi ...
- mfs使用指引
客户端工具集 mfsgetgoal #设定副本数 mfssetgoal #获取副本数 mfscopygoal # mfsgetsclass mfssetsclass mfscopysclass mfs ...
- yii依赖注入
为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Service Locator) ...