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 的值越小,说明越先被执行。
相关文章
- 【AOP】Spring AOP 和 AspectJ
- spring boot系列--spring security (基于数据库)登录和权限控制
- Elasticsearch集群、Java客户端、Spring Data Elasticsearch
- Spring Cloud Gateway网关原理分析
- Java Spring中同时访问多种不同数据库
- spring cloud confg-client的操作
- Spring Boot(十七):使用 Spring Boot 上传文件
- 一招搞定 Spring Boot 可视化监控!
- 精品spring boot+MySQL微人事系统设计与实现vue
- spring jdbc分离数据库代码和java代码
- IntelliJ IDEA通过Spring配置连接MySQL数据库
- [置顶] 如何使用c3p0+spring连接oracle数据库
- spring-data-jpa实体类继承抽象类如何映射父类的属性到数据库
- 正确理解Spring事务和数据库事务和锁
- 多事务运行并发问题spring学习笔记——数据库事务并发与锁详解
- spring-boot-mail
- Spring Cloud构建微服务架构
- spring获取session设置session
- springboot1——spring相关入门
- Spring Boot 切面AOP实现权限校验(实例演示与注解全解)
- 【微服务~原始真解】Spring Cloud —— 访问数据库整合Druid数据源
- spring的事务是什么?与数据库的事务是否一样
- 在Spring Boot中使用数据库事务
- Spring进行TestNG测试中无法插入、删除数据库数据(access)的解决
- Spring Batch ItemReader组件-读数据库
- 通过spring抽象路由数据源+MyBatis拦截器实现数据库自动读写分离
- 分离你的spring配置文件,让结构更清晰
- Spring中三种获取ApplicationContext的方法