数据库读写分离(aop方式完整实现)
2015-06-12 15:14
501 查看
最近项目要支持读写分离, 网上找了很多,但都是不太完整,我自己整理了下供大家参考。
我的项目使用的框架: springMvc+spring+hibernate+springJPA+maven, 数据库连接池用阿里的druid。
1. 新建一个DynamicDataSource类, 继承spring的AbstractRoutingDataSource 类,
并重写determineCurrentLookupKey()方法,如下:
2. 新建DataSourceSwitcher类, 实现数据源选择:
3. 新建切面类, 判断如果调用方法以query,list,get方法开头的, 切换为查询库:
4. spring配置文件中, 配置数据源:
5. AOP配置(注意, 可以在service层切换(推荐), 也可以在控制器层切换):
截图为在控制层切换配置, 附件中的context.xml中给的是在service/dao层切换的配置方式。
6. mvc层支持aop(如果aop切换配置在控制层, 则需要配置这步):
7. 特殊类可以硬编码:
切换到主库 : DataSourceSwitcher.setMaster();
比如 , 登录拦截器RoleGenInterceptor.java --> genLocalSession()
附件下载地址
我的项目使用的框架: springMvc+spring+hibernate+springJPA+maven, 数据库连接池用阿里的druid。
1. 新建一个DynamicDataSource类, 继承spring的AbstractRoutingDataSource 类,
并重写determineCurrentLookupKey()方法,如下:
package com.dataSource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * 数据源动态切换类 * <p> * Copyright: Copyright (c) 2015-3-9 下午3:15:19 * <p> * Company: * <p> * * @author macl@c-platform.com * @version 1.0.0 */ public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceSwitcher.getDataSource(); } }
2. 新建DataSourceSwitcher类, 实现数据源选择:
package com.dataSource; import org.springframework.util.Assert; /** * 数据源选择类 * <p> * Copyright: Copyright (c) 2015-3-9 下午3:14:55 * <p> * Company: * <p> * * @author macl@c-platform.com * @version 1.0.0 */ public class DataSourceSwitcher { private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); /** 主库(写库) **/ public static final String MASTER_DATA_SOURCE = "master"; /** 从库(读库) **/ public static final String SLAVE_DATA_SOURCE = "slave"; public static void setDataSource(String dataSource) { Assert.notNull(dataSource, "dataSource cannot be null"); contextHolder.set(dataSource); } public static void setMaster() { clearDataSource(); } public static void setSlave() { setDataSource(SLAVE_DATA_SOURCE); } public static String getDataSource() { return (String) contextHolder.get(); } public static void clearDataSource() { contextHolder.remove(); } }
3. 新建切面类, 判断如果调用方法以query,list,get方法开头的, 切换为查询库:
package com.dataSource; import java.lang.reflect.Method; import java.util.List; import org.apache.log4j.Logger; import org.springframework.aop.AfterReturningAdvice; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.aop.ThrowsAdvice; /** * 配置AOP切面类,动态切换读/写数据库。 * <p> * Copyright: Copyright (c) 2015-3-9 下午3:16:51 * <p> * Company: * <p> * * @author macl@c-platform.com * @version 1.0.0 */ public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice { private static final Logger log = Logger.getLogger(DataSourceAdvice.class); private String logInfo; // 需要切换到从库(读库)的方法名前缀 private List<String> slaveMethods; /** * service方法执行之前被调用. */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { logInfo = String.format("before切入点:%s-->%s(),切换到:", target.getClass().getName(), method.getName()); String methodName = method.getName(); boolean hasSwitchedSlave = false; for (String slaveMethod : slaveMethods) { if (methodName.startsWith(slaveMethod)) { if (log.isDebugEnabled()) { log.debug(logInfo + DataSourceSwitcher.SLAVE_DATA_SOURCE); } hasSwitchedSlave = true; DataSourceSwitcher.setSlave(); break; } } if (!hasSwitchedSlave) { if (log.isDebugEnabled()) { log.debug(logInfo + "切换到:" + DataSourceSwitcher.MASTER_DATA_SOURCE); } DataSourceSwitcher.setMaster(); } } /** * service方法执行完之后被调用. */ @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { } /** * 抛出Exception之后被调用。 * * @param method * @param args * @param target * @param ex * @throws Throwable */ public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable { logInfo = String.format("after throwing:%s类中%s方法,", target.getClass().getName(), method.getName()); log.error(logInfo + "发生异常:" + ex.getMessage() + ",切换到:" + DataSourceSwitcher.SLAVE_DATA_SOURCE); DataSourceSwitcher.setSlave(); } public List<String> getSlaveMethods() { return slaveMethods; } public void setSlaveMethods(List<String> slaveMethods) { this.slaveMethods = slaveMethods; } }
4. spring配置文件中, 配置数据源:
5. AOP配置(注意, 可以在service层切换(推荐), 也可以在控制器层切换):
截图为在控制层切换配置, 附件中的context.xml中给的是在service/dao层切换的配置方式。
6. mvc层支持aop(如果aop切换配置在控制层, 则需要配置这步):
7. 特殊类可以硬编码:
切换到主库 : DataSourceSwitcher.setMaster();
比如 , 登录拦截器RoleGenInterceptor.java --> genLocalSession()
附件下载地址
相关文章推荐
- 批量解密SQLSERVER数据库中的各种对象的工具dbForge SQL Decryptor2.1.11
- oracle数据库管理之表空间
- MySQL出现too many connections(1040)错误的解决办法
- win7 下面操作memcache
- mongodb优化基本方案
- redis服务端最大客户端数
- ORACLE 注册备份集信息方法(catalog backuppiece)
- 复制读写规则
- sql server 2005针对内存管理优化 内存占用大轻松解决
- mysql计算指定时间内TPS
- mysql开发需求
- Oracle集群文件系统(OCFS2)
- oracle数据库导出备份导入恢复
- JAVA单例MongoDB工具类
- Oracle 11.2.0.3 Download Link
- mysql复制延迟监控脚本
- Oracle 安装报SGA size can not be greater than maximum shared memory segment size(0)
- MongoDB聚合命令比较
- MongoDB聚合命令比较
- 安装安全狗后,sql2000安装出现输入CDKEY