spring 配置多数据源(mysql读写分离)
前段时间刚换了家新公司,然后看项目代码里用了数据库读写分离的架构,然后好奇扒了代码简单看了下,总体来说就是运用spring aop切面方式来实现的。看明白后就在自己的个人小项目里运用了下,测试OK,所以下面总结下流程:
1、首先定义一个数据源注解,它有两个值,一个对应写库(主库),一个对应读库(从库)
package com.jdd.ds; import java.lang.annotation.*; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DataSource { String DATA_SOURCE_READ = "dataSourceRead"; String DATA_SOURCE_WRITE = "dataSourceWrite"; String name() default "dataSourceWrite"; }
2、在需要拦截的方法上加上该注解
package com.jdd.service.impl; import com.jdd.dao.UserDao; import com.jdd.ds.DataSource; import com.jdd.pojo.User; import com.jdd.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service("userService") public class UserServiceImpl implements UserService{ @Autowired private UserDao userDao; @DataSource(name=DataSource.DATA_SOURCE_READ) @Override public User getUserByNameAndPassword(String name, String password) { return userDao.getUserByNameAndPassword(name, password); } @DataSource(name=DataSource.DATA_SOURCE_WRITE) @Override public int insertUser(User user) { return userDao.insertUser(user); } }
3、然后在配置文件里加上aop切面配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 扫描包加载Service实现类 --> <context:component-scan base-package="com.jdd.service"></context:component-scan> <bean id="dataSourceExchange" class="com.jdd.ds.DataSourceExchange"></bean> <aop:config> <aop:aspect ref="dataSourceExchange"> <aop:around method="execute" pointcut="within(com.jdd.service.impl.*)"></aop:around> </aop:aspect> </aop:config> </beans>
4、然后我们要在切面类里,获取到方法上的dataSource注解里设置的值,从而决定使用哪个数据源
package com.jdd.ds; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Method; public class DataSourceExchange { private static Logger logger = LoggerFactory.getLogger(DataSourceExchange.class); public Object execute(ProceedingJoinPoint pjp){ logger.info("DataSourceExchange==>"); Object obj = null; Signature signature = pjp.getSignature(); MethodSignature methodSignature = (MethodSignature)signature; Method targetMethod = methodSignature.getMethod(); Method realMethod = null; try { realMethod = pjp.getTarget().getClass().getDeclaredMethod(signature.getName(), targetMethod.getParameterTypes()); if(realMethod.isAnnotationPresent(DataSource.class)){ DataSource datasource = (DataSource) realMethod.getAnnotation(DataSource.class); DataSourceContext.setDbType(datasource.name()); logger.info(realMethod.getName() +" set dbtype==>"+datasource.name()); }else{ DataSourceContext.setDbType("dataSourceWrite"); } obj = pjp.proceed(); } catch (Throwable t) { t.printStackTrace(); } logger.info(realMethod.getName()+" clear datatype==>"); DataSourceContext.clearDbType(); return obj; } }
在方法执行前,设置具体数据源,然后方法执行完后,再清除掉该值。
注:注意上面的通过反射获取业务方法的代码, 开始的时候用
MethodSignature signature = (MethodSignature)pjp.getSignature();
Method method = signature.getMethod();
发现通过这种方法获取的method,它是没有注解信息的。后来在网上搜了下,大概说是这种方法获取的是代理方法,不是目标方法。代理方法是不带注解信息的,所以这块注意下。
5、下面看下 DataSourceContext 类,作用自然就是设置数据源上下文。
package com.jdd.ds; public class DataSourceContext { public static final String DATA_SOURCE_READ = "dataSourceRead"; public static final String DATA_SOURCE_WRITE = "dataSourceWrite"; private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public DataSourceContext(){ } public static void setDbType(String dbType){ contextHolder.set(dbType); } public static String getDbType(){ return (String)contextHolder.get(); } public static void clearDbType(){ contextHolder.remove(); } }
6、下面定义 MultipleDataSource类, 继承与spring的 AbstractRoutingDataSource类, 并重写它的 determineCurrentLookupKey 方法, 作用就是从上下文获取当前线程使用的数据源标识:
package com.jdd.ds; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class MultipleDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { Object key = DataSourceContext.getDbType(); if(key != null){ this.logger.info("当前线程使用的数据源标识为 [ " + key.toString() + " ]."); } return key; } }
7、最后在 配置文件 applicationContext-mysql.xml 里 配上数据源
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd"> <!-- 加载配置文件 --> <context:property-placeholder location="classpath:resource/*.properties" /> <!-- 数据库连接池 --> <bean id="dataSourceWrite" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="${url.write}" /> <property name="username" value="${username.write}" /> <property name="password" value="${password.write}" /> <property name="maxActive" value="10" /> <property name="minIdle" value="5" /> </bean> <bean id="dataSourceRead" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="${url.read}" /> <property name="username" value="${username.read}" /> <property name="password" value="${password.read}" /> <property name="maxActive" value="10" /> <property name="minIdle" value="5" /> </bean> <bean id="multipleDataSource" class="com.jdd.ds.MultipleDataSource"> <property name="defaultTargetDataSource" ref="dataSourceWrite" /> <property name="targetDataSources"> <map> <entry value-ref="dataSourceWrite" key="dataSourceWrite"></entry> <entry value-ref="dataSourceRead" key="dataSourceRead"></entry> </map> </property> </bean> <!-- sqlsessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:mybatis/SqlMapConfig.xml"></property> <property name="dataSource" ref="multipleDataSource"></property> <property name="mapperLocations" value="classpath:com/jdd/mapper/*.xml"></property> </bean> </beans>
8、到这里和spring相关的配置基本就配完了, 其实后面还要再配置一下 mysql的主从复制,就是对写库的操作都同步到从库,这样写库从库的数据才一致。具体配置操作我就不写了,可以自行到网上搜索。
spring 配置多数据源(mysql读写分离)的更多相关文章
- 使用Spring配置动态数据源实现读写分离
最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考.关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!-- ...
- 阿里P7教你如何使用 Spring 配置动态数据源实现读写分离
最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考. 关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!- ...
- 使用 Spring 配置动态数据源实现读写分离
关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!--读数据源配置--><bean id="readData ...
- spring 配置双数据源并读写分离
摘自 开源项目Ibase4j 关键思想在于AbstractRoutingSource 类 还有方法名称和切入点去控制使用哪个数据源 1.首先在配置文件配置多个数据源 并且交给继承自spri ...
- spring集成mybatis实现mysql读写分离
前言 在网站的用户达到一定规模后,数据库因为负载压力过高而成为网站的瓶颈.幸运的是目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库的数据更新同步到另一台服务器上. ...
- mybatis用spring的动态数据源实现读写分离
一.环境: 三个mysql数据库.一个master,两个slaver.master写数据,slaver读数据. 二.原理: 借助Spring的 AbstractRoutingDataSource 这个 ...
- Spring Boot2(四):使用Spring Boot多数据源实现读写分离
前言 实际业务场景中,不可能只有一个库,所以就有了分库分表,多数据源的出现.实现了读写分离,主库负责增改删,从库负责查询.这篇文章将实现Spring Boot如何实现多数据源,动态数据源切换,读写分离 ...
- ThinkPHP配置简单的mysql读写分离
ThinkPHP内置了分布式数据库的支持,包括主从式数据库的读写分离,但是分布式数据库必须是相同的数据库类型. 配置DB_DEPLOY_TYPE 为1 可以采用分布式数据库支持.如果采用分布式数据库, ...
- 原理解密 → Spring AOP 实现动态数据源(读写分离),底层原理是什么
开心一刻 女孩睡醒玩手机,收到男孩发来一条信息:我要去跟我喜欢的人表白了! 女孩的心猛的一痛,回了条信息:去吧,祝你好运! 男孩回了句:但是我没有勇气说不来,怕被打! 女孩:没事的,我相信你!此时女孩 ...
- Spring配置动态数据源-读写分离和多数据源
在现在互联网系统中,随着用户量的增长,单数据源通常无法满足系统的负载要求.因此为了解决用户量增长带来的压力,在数据库层面会采用读写分离技术和数据库拆分等技术.读写分离就是就是一个Master数据库,多 ...
随机推荐
- CCM和GCM
分组密码链接-消息认证码--CCM Counter with CBC-MAC 组成CCM的关键算法是AES加密算法.CTR工作模式和CMAC认证算法,在加密和MAC算法中共用一个密钥K. CCM ...
- FFmpeg API 变更记录
最近一两年内FFmpeg项目发展的速度很快,本来是一件好事.但是随之而来的问题就是其API(接口函数)一直在发生变动.这么一来基于旧一点版本的FFmpeg的程序的代码在最新的类库上可能就跑不通了. 例 ...
- JAVA 继承基本类、抽象类、接口
Java是一个面向对象的语言,java面向对象一般有三大特征:封装.继承.多态. 封装:就是把一些属性和方法封装到一个类里. 继承:就如子类继承父类的一些属性和方法. 多态:就如一个父类有多个不同特色 ...
- Unity2D Sprite灰白图(Unity3D开发之十一)
猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=596 昨晚看到群里问到2DSpr ...
- Linux Debugging(一): 使用反汇编理解C++程序函数调用栈
拿到CoreDump后,如果看到的地址都是????,那么基本上可以确定,程序的栈被破坏掉了.GDB也是使用函数的调用栈去还原"事故现场"的.因此理解函数调用栈,是使用GDB进行现场 ...
- python的sys模块
Sys模块函数之多,我只能选取自己认为比较实用的一些函数列在此处.借马云找员工的说法,"找最合适的而不是最天才的",这句话,我个人觉得在很多方面都能适应,学习也不在话下.Sys模块 ...
- 72【leetcode】经典算法- Lowest Common Ancestor of a Binary Search Tree(lct of bst)
题目描述: 一个二叉搜索树,给定两个节点a,b,求最小的公共祖先 _______6______ / \ ___2__ ___8__ / \ / \ 0 _4 7 9 / \ 3 5 例如: 2,8 - ...
- MySQL学习笔记_5_SQL语言的设计与编写(上)
SQL语言的设计与编写(上) 一.SQL语句分类 数据定义语言(DDL): 用于定义和管理数据对象,包括数据库.数据表.视图.索引等.例如:CREATE.DROP.ALTER等语句. 数据操作语言(D ...
- Html5学习之旅-html5的留言记事本开发(17)
web留言记事本的开发 !!!!!代码如下 index.html的代码 <!DOCTYPE html> <html lang="en"> <head& ...
- Zookeeper介绍 Zookeeper搭建 Zookeeper集群搭建
关键字:分布式 背景 随着互联网技术的高速发展,企业对计算机系统的技术.存储能力要求越来越高,最简单的证明就是出现了一些诸如:高并发.海量存储这样的词汇.在这样的背景 下,单纯依靠少量 ...