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数据库,多 ...
随机推荐
- Hadoop:Hadoop简介及环境配置
http://blog.csdn.net/pipisorry/article/details/51243805 Hadoop简介 下次写上... 皮皮blog 配置hadoop环境可能出现的问题 每次 ...
- UNIX环境高级编程——线程私有数据
线程私有数据(Thread-specific data,TSD):存储和查询与某个线程相关数据的一种机制. 在进程内的所有线程都共享相同的地址空间,即意味着任何声明为静态或外部变量,或在进程堆声明的变 ...
- Android初级教程理论知识(第四章内容提供器)
之前第三章理论知识写到过数据库.数据库是在程序内部自己访问自己.而内容提供器是访问别的程序数据的,即跨程序共享数据.对访问的数据也无非就是CRUD. 内容提供者 应用的数据库是不允许其他应用访问的 内 ...
- java设计模式---三种工厂模式
工厂模式提供创建对象的接口. 工厂模式分为三类:简单工厂模式(Simple Factory), 工厂方法模式(Factory Method)和抽象工厂模式(Abstract Factory).GOF在 ...
- 一个大数据方案:基于Nutch+Hadoop+Hbase+ElasticSearch的网络爬虫及搜索引擎
网络爬虫架构在Nutch+Hadoop之上,是一个典型的分布式离线批量处理架构,有非常优异的吞吐量和抓取性能并提供了大量的配置定制选项.由于网络爬虫只负责网络资源的抓取,所以,需要一个分布式搜索引擎, ...
- Miscellaneous Articles
标记一下,慢慢看 http://www.oracle-base.com/articles/misc/articles-misc.php Miscellaneous Articles DBA Deve ...
- mongoDB基本使用(二)
数据库基本操作 连接到mongoDB服务器 ./bin/mongo 127.0.0.1:12345 查看当前数据库 > show dbs admin (empty) local 0.078 ...
- unity使用UGUI创建摇杆
1.现在unity做一个项目,各种插件各种包,于是项目资源就无限变大了,其实一些简单的功能可以自己写,这里就是试着使用UGUI编写一个摇杆功能 2.脚本如下: using UnityEngine; u ...
- EventBus的其他常用函数
上一篇EventBus最简易使用方式介绍了EventBus最简易的使用方式,摆脱了叽里呱啦+图片的长篇大论.目的是为了让刚开始接触的人们不晕头转向.那么这篇..我也要开始图片+叽里呱啦了. 转载请注明 ...
- Linux学习笔记 --iptables防火墙配置
iptables防火墙配置 一.防火墙简介 1.功能: 1)通过源端口,源IP地址,源MAC地址,包中特定标记和目标端口,IP,MAC来确定数据包是否可以通过防火墙 2)分割内网和外网[附带的路由器的 ...