博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用Spring AOP实现MySQL数据库读写分离案例分析
阅读量:5819 次
发布时间:2019-06-18

本文共 4785 字,大约阅读时间需要 15 分钟。

使用Spring AOP实现MySQL数据库读写分离案例分析

一、前言

分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量。

在进行数据库读写分离的时候,我们首先要进行数据库的主从配置,最简单的是一台Master和一台Slave(大型网站系统的话,当然会很复杂,这里只是分析了最简单的情况)。通过主从配置主从数据库保持了相同的数据,我们在进行读操作的时候访问从数据库Slave,在进行写操作的时候访问主数据库Master。这样的话就减轻了一台服务器的压力。

在进行读写分离案例分析的时候。首先,配置数据库的主从复制,可以选择下面的这个方法:

当然,只是简单的为了看一下如何用代码的方式实现数据库的读写分离,完全不必要去配置主从数据库,只需要两台安装了 相同数据库的机器就可以了。

二、实现读写分离的两种方法

具体到开发中,实现读写分离常用的有两种方式:

  • 第一种方式是我们最常用的方式,就是定义2个数据库连接,一个是MasterDataSource,另一个是SlaveDataSource。更新数据时我们读取MasterDataSource,查询数据时我们读取SlaveDataSource。这种方式很简单,我就不赘述了。
  • 第二种方式动态数据源切换,就是在程序运行时,把数据源动态织入到程序中,从而选择读取主库还是从库。主要使用的技术是:Annotation,Spring AOP ,反射。

下面会详细的介绍实现方式。

三、Aop实现主从数据库的读写分离案例

1、项目代码地址

目前该Demo的项目地址在开源中国 码云 上边:

使用Spring AOP实现MySQL数据库读写分离案例分析

2、项目结构

使用Spring AOP实现MySQL数据库读写分离案例分析

上图中,除了标记的代码,其他的主要是配置代码和业务代码。

3、具体分析

该项目是SSM框架的一个demo,Spring、Spring MVC和MyBatis,具体的配置文件不在过多介绍。

(1)UserContoller模拟读写数据

<pre style="margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; word-break: break-word;">

/** * Created by xuliugen on 2016/5/4. */@Controller@RequestMapping(value = "/user", produces = {"application/json;charset=UTF-8"})public class UserController { @Inject private IUserService userService; //http://localhost:8080/user/select.do @ResponseBody @RequestMapping(value = "/select.do", method = RequestMethod.GET) public String select() { User user = userService.selectUserById(123); return user.toString(); } //http://localhost:8080/user/add.do @ResponseBody @RequestMapping(value = "/add.do", method = RequestMethod.GET) public String add() { boolean isOk = userService.addUser(new User("333", "444")); return isOk == true ? "shibai" : "chenggong"; }}

模拟读写数据,调用IUserService 。

(2)spring-db.xml读写数据源配置

<pre style="margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; word-break: break-word;">

上述配置中,配置了readDataSource和writeDataSource两个数据源,但是交给SqlSessionFactoryBean进行管理的只有dataSource,其中使用到了:com.xuliugen.choosedb.demo.aspect.ChooseDataSource 这个是进行数据库选择的。

<pre style="margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; word-break: break-word;">

配置了数据库具体的那些是读哪些是写的前缀关键字。ChooseDataSource的具体代码如下:

(3)ChooseDataSource

<pre style="margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; word-break: break-word;">

/** * 获取数据源,用于动态切换数据源 */public class ChooseDataSource extends AbstractRoutingDataSource { public static Map
> METHOD_TYPE_MAP = new HashMap
>(); /** * 实现父类中的抽象方法,获取数据源名称 * @return */ protected Object determineCurrentLookupKey() { return DataSourceHandler.getDataSource(); } // 设置方法名前缀对应的数据源 public void setMethodType(Map
map) { for (String key : map.keySet()) { List
v = new ArrayList
(); String[] types = map.get(key).split(","); for (String type : types) { if (StringUtils.isNotBlank(type)) { v.add(type); } } METHOD_TYPE_MAP.put(key, v); } }}

(4)DataSourceAspect进行具体方法的AOP拦截

<pre style="margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; word-break: break-word;">

/** * 切换数据源(不同方法调用不同数据源) */@Aspect@Component@EnableAspectJAutoProxy(proxyTargetClass = true)public class DataSourceAspect { protected Logger logger = LoggerFactory.getLogger(this.getClass()); @Pointcut("execution(* com.xuliugen.choosedb.demo.mybatis.dao.*.*(..))") public void aspect() { } /** * 配置前置通知,使用在方法aspect()上注册的切入点 */ @Before("aspect()") public void before(JoinPoint point) { String className = point.getTarget().getClass().getName(); String method = point.getSignature().getName(); logger.info(className + "." + method + "(" + StringUtils.join(point.getArgs(), ",") + ")"); try { for (String key : ChooseDataSource.METHOD_TYPE_MAP.keySet()) { for (String type : ChooseDataSource.METHOD_TYPE_MAP.get(key)) { if (method.startsWith(type)) { DataSourceHandler.putDataSource(key); } } } } catch (Exception e) { e.printStackTrace(); } }}

(5)DataSourceHandler,数据源的Handler类

<pre style="margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; word-break: break-word;">

package com.xuliugen.choosedb.demo.aspect;/** * 数据源的Handler类 */public class DataSourceHandler { // 数据源名称线程池 public static final ThreadLocal
holder = new ThreadLocal
(); /** * 在项目启动的时候将配置的读、写数据源加到holder中 */ public static void putDataSource(String datasource) { holder.set(datasource); } /** * 从holer中获取数据源字符串 */ public static String getDataSource() { return holder.get(); }}

主要代码,如上所述。

转载于:https://blog.51cto.com/14257804/2383503

你可能感兴趣的文章
Linux内核中的printf实现【转】
查看>>
第四章 mybatis批量insert
查看>>
Java并发框架——什么是AQS框架
查看>>
【数据库】
查看>>
Win配置Apache+mod_wsgi+django环境+域名
查看>>
第四届中国汽车产业信息化技术创新峰会将于6月在沪召开
查看>>
linux清除文件内容
查看>>
WindowManager.LayoutParams 详解
查看>>
find的命令的使用和文件名的后缀
查看>>
Android的Aidl安装方法
查看>>
Linux中rc的含义
查看>>
曾鸣:区块链的春天还没有到来| 阿里内部干货
查看>>
如何通过Dataworks禁止MaxCompute 子账号跨Project访问
查看>>
js之无缝滚动
查看>>
Django 多表联合查询
查看>>
logging模块学习:basicConfig配置文件
查看>>
Golang 使用 Beego 与 Mgo 开发的示例程序
查看>>
ntpdate时间同步
查看>>
+++++++子域授权与编译安装(一)
查看>>
asp.net怎样在URL中使用中文、空格、特殊字符
查看>>