Spring+Hibernate+MySQL的主从分离/读写分离问题(2)
来源:互联网 发布:js解除绑定click事件 编辑:程序博客网 时间:2024/04/28 15:01
这里上具体代码,因为没时间做单独的可运行实例,所以这里只贴关键的代码。
DataSource的配置
<bean id="parentDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"> <property name="defaultAutoCommit" value="${hibernate.defaultAutoCommit}" /> <property name="maxTotal" value="${hibernate.maxTotal}" /> <property name="maxIdle" value="${hibernate.maxIdle}" /> <property name="initialSize" value="${hibernate.initialSize}" /> <property name="testOnBorrow" value="${hibernate.testOnBorrow}" /> <property name="validationQuery" value="${hibernate.validationQuery}" /> <property name="connectionInitSqls" value="set names utf8mb4" /> </bean> <bean id="masterDataSource" class="org.apache.commons.dbcp2.BasicDataSource" parent="parentDataSource"> <property name="driverClassName" value="${jdbc.master.driver}" /> <property name="url" value="${jdbc.master.url}" /> <property name="username" value="${jdbc.master.username}" /> <property name="password" value="${jdbc.master.password}" /> </bean> <bean id="slaveDataSource" class="org.apache.commons.dbcp2.BasicDataSource" parent="parentDataSource"> <property name="driverClassName" value="${jdbc.slave.driver}" /> <property name="url" value="${jdbc.slave.url}" /> <property name="username" value="${jdbc.slave.username}" /> <property name="password" value="${jdbc.slave.password}" /> </bean>
ReplicationRoutingDataSource为AbstractRoutingDataSource的实现
<bean id="dataSource" class="com.xxx.xxx.ReplicationRoutingDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="MASTER" value-ref="masterDataSource"/> <entry key="SLAVE" value-ref="slaveDataSource"/> </map> </property> <property name="defaultTargetDataSource" ref="masterDataSource"/> </bean>
ReplicationRoutingDataSource 写法
public class ReplicationRoutingDataSource extends AbstractRoutingDataSource { private Map<Object, Object> tempTargetDataSources = null; public ReplicationRoutingDataSource(){ DynamicDataSourceAspect.replicationRoutingDataSource = this; } @Override public void setTargetDataSources(Map<Object, Object> targetDataSources) { super.setTargetDataSources(targetDataSources); tempTargetDataSources = targetDataSources; } public Map<Object, Object> getTargetDataSources() { return tempTargetDataSources; } @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceContextHolder.getDataSourceType(); }}
DataSource的动态管理类通过ThreadLocal保证线程安全
public class DynamicDataSourceContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static List<String> dataSourceIds = new ArrayList<>(); public static void setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType); } public static String getDataSourceType() { return contextHolder.get(); } public static void clearDataSourceType() { contextHolder.remove(); } /** * 判断指定DataSrouce当前是否存在 * * @param dataSourceId * @return * @author zxl * @create */ public static boolean containsDataSource(String dataSourceId){ return dataSourceIds.contains(dataSourceId); }}
自定义注解
@Target({ ElementType.METHOD, ElementType.TYPE })@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface TargetDataSource { String name();}
切面类,通过自定义注解TargetDataSource作为切入点
public class DynamicDataSourceAspect { private Logger logger = Logger.getLogger(DynamicDataSourceAspect.class); public static ReplicationRoutingDataSource replicationRoutingDataSource = null; public void changeDataSource(JoinPoint point, TargetDataSource ds) throws Throwable { String dsId = ds.name(); if (replicationRoutingDataSource!=null &&!replicationRoutingDataSource.getTargetDataSources().containsKey(dsId)) { logger.error("DataSource not exist "+ds.name() + point.getSignature()); } else { logger.debug("Use DataSource : {} > {}"+ds.name()+ point.getSignature()); DynamicDataSourceContextHolder.setDataSourceType(ds.name()); } } public void restoreDataSource(JoinPoint point, TargetDataSource ds) { logger.debug("Revert DataSource : {} > {}"+ds.name()+ point.getSignature()); DynamicDataSourceContextHolder.clearDataSourceType(); }}
AOP配置,这里请注意,由于配置到Contorller层的缘故,如果发现配置无效,请检查是否出现AOP配置冲突
<!-- 指定DataSourceAOP,用于动态切换DataSource --> <bean id="dataSourceAspect" class="com.xxx.xxx.DynamicDataSourceAspect" /> <aop:config> <aop:aspect id="aspectDataSourceConfig" ref="dataSourceAspect" > <aop:before method="changeDataSource" pointcut="@annotation(ds)"/> <aop:after method="restoreDataSource" pointcut="@annotation(ds)"/> </aop:aspect> </aop:config>
使用方法
@Controller@RequestMapping(value = "/test")public class TestController extends BaseController { @RequestMapping(value = "/testmaster", method = {RequestMethod.POST, RequestMethod.GET }) @ResponseBody @TargetDataSource(name="SLAVE") public String onTestSlave(HttpServletRequest request, HttpServletResponse response) { //具体业务 return "result"; } @RequestMapping(value = "/testslave", method = {RequestMethod.POST, RequestMethod.GET }) @ResponseBody @TargetDataSource(name="MASTER") public String onTestMaster(HttpServletRequest request, HttpServletResponse response) { //具体业务 return "result"; }}
参考
1. http://blog.csdn.net/caomiao2006/article/details/38989789
2. http://stackoverflow.com/questions/30023704/database-routing-using-abstractroutingdatasource
0 0
- Spring+Hibernate+MySQL的主从分离/读写分离问题(2)
- Spring+Hibernate+MySQL的主从分离/读写分离问题(1)
- spring-hibernate-mysql实现主从读写分离
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- mysql主从读写分离
- spring读写分离(mysql主从复制<3>)
- MySQL 主从配置和基于Spring 的读写分离
- Mysql的主从复制与读写分离
- mysql的主从复制 读写分离
- mysql数据库的主从配置读写分离
- MySQL的主从复制以及读写分离
- mysql的主从复制,读写分离
- mysql的读写分离和主从复制
- Android工作笔记:Android路径大全
- 有硬件依赖或其他依赖的测试驱动开发
- 顺序表应用&4:元素位置互换之移位&逆置算法
- Unity5-ABSystem(一):AssetBundle原理
- JavaScript中的call、apply、bind深入理解
- Spring+Hibernate+MySQL的主从分离/读写分离问题(2)
- 互联网架构,如何进行容量设计?
- zoj 3327 Friend Number 枚举 分类讨论 模拟
- 表格隔行变色怎么写?
- 编译git遇到的perl-ExtUtils-MakeMaker错误
- Android N使用Ubuntu 14.04系统搭建编译环境
- linux c++ 多线程代码 对文件的读写
- notepad中安装Emmet插件
- ViewPager+Fragment取消预加载(实现只加载一页的效果)