spring结合mybatis实现数据库读写分离
随着系统用户访问量的不断增加,数据库的频繁访问将成为我们系统的一大瓶颈之一。由于项目前期用户量不大,我们实现单一的数据库就能完成。但是后期单一的数据库根本无法支撑庞大的项目去访问数据库,那么如何解决这个问题呢?
实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的CPU较多,从而影响用户体验。我们通常的做法就是把查询从主库中抽取出来,采用多个从库,使用负载均衡,减轻每个从库的查询压力。
采用读写分离技术的目标:有效减轻Master库的压力,又可以把用户查询数据的请求分发到不同的Slave库,从而保证系统的健壮性。我们看下采用读写分离的背景。
本人在项目开发初期的时候就设计了一个简单的读写分离,现在我把demo分享给大家。
采用技术Spring + mybatis
首先定义一个annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
public String value();
}
再定义一个HandleDataSource
public class HandleDataSource {
public static final ThreadLocal holder = new ThreadLocal();
public static void putDataSource(String datasource) {
holder.set(datasource);
}
public static String getDataSource() {
return holder.get();
}
}
定义一个切面
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
public class DataSourceAspect {
public void pointCut() {
};
public void before(JoinPoint point) {
Object target = point.getTarget();// 拦截的实体类
String method = point.getSignature().getName();// 拦截的方法名称
Class[] classz = target.getClass().getInterfaces();
Class[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes();// 拦截的方法参数类型
try {
Method m = classz[0].getMethod(method, parameterTypes);
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource data = m.getAnnotation(DataSource.class);
HandleDataSource.putDataSource(data.value());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
获取数据源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class ChooseDataSource extends AbstractRoutingDataSource {
protected Object determineCurrentLookupKey() {
return HandleDataSource.getDataSource();
}
}
配置XMl
classpath*:mysql.propertiescom.mysql.jdbc.Driver${jdbc.url}${jdbc.user}${jdbc.password}SELECT 1 FROM DUAL32510010000true60com.mysql.jdbc.Driver${jdbc.url.read}${jdbc.user.read}${jdbc.password.read}SELECT 1 FROM DUAL32510010000true60
注解到service接口上面
源码地址
http://ccblog.oss-cn-hangzhou.aliyuncs.com/file/dbShard_demo.rar
数据库表就一张 根据mybatis的xml大家自己建一下
另外这里还有一个瑕疵就是,当你使用注解事务的时候系统只能读取默认的数据源,这个问题主要是因为spring的事务和自定义的aop存在一个先后顺序的问题
Spring中的事务是通过aop来实现的,当我们自己写aop拦截的时候,会遇到跟spring的事务aop执行的先后顺序问题,比如说动态切换数据源的问题,如果事务在前,数据源切换在后,会导致数据源切换失效,所以就用到了Order(排序)这个关键字.
我们可以通过在@AspectJ的方法中实现org.springframework.core.Ordered 这个接口来定义order的顺序,order 的值越小,说明越先被执行。
最新文章
- Java 反射 使用总结
- pycharm配置字体问题
- jQuery lazyload插件详解和问题解答
- geoserver 安装 sql server 插件
- 苹果App store 2015最新审核标准公布(2015.3)
- linux目录权限小记
- POJ1505&;amp;&;amp;UVa714 Copying Books(DP)
- Fileupload-1.2.1使用简单样例
- Spring Resource之应用上下文和资源路径
- FFmpeg 常用命令收集
- multiset的erase()操作中出现跳过元素的问题
- Django+Vue打造购物网站(五)
- uboot使用笔记
- MySQL :: Fatal error: Can&;#039;t change to run as user &;#039;mysql&;#039;. Please check that the user exists!
- C# MD5 加密
- ajax调用WebService 不能跨域
- 关于IBatisNet的配置文件中数据库连接字符串加密处理
- Mongo命令批量更新某一数组字段的顺序
- 16 款最流行的JavaScript 框架
- C++中的函数
热门文章
- java多态--算法实现就是多态
- cocos2d-x retain和release倒底怎么玩?
- ASP.NET :Virtual Application vs Virtual Directory
- [LNU.Machine Learning.Question.1]梯度下降方法的一些理解
- CentOS 7 修改时区
- BadgeValueView
- python resize
- EditText的监听器和自定义回车事件
- Eclipse启动时提示Fail to create the Java Virtual Machine的解决方法
- c# action<;>; func<;>; 这2个委托怎么用和理解