- 浏览: 21499294 次
- 性别:
博客专栏
-
跟我学spring3
浏览量:2417759
-
Spring杂谈
浏览量:3008050
-
跟开涛学SpringMVC...
浏览量:5638946
-
Servlet3.1规范翻...
浏览量:259806
-
springmvc杂谈
浏览量:1597022
-
hibernate杂谈
浏览量:250104
-
跟我学Shiro
浏览量:5858140
-
跟我学Nginx+Lua开...
浏览量:701782
-
亿级流量网站架构核心技术
浏览量:784896
文章分类
- 全部博客 (329)
- 跟我学Nginx+Lua开发 (13)
- 跟我学spring (54)
- 跟开涛学SpringMVC (34)
- spring4 (16)
- spring杂谈 (50)
- springmvc杂谈 (22)
- 跟我学Shiro (26)
- shiro杂谈 (3)
- hibernate杂谈 (10)
- java开发常见问题分析 (36)
- 加速Java应用开发 (5)
- Servlet 3.1规范[翻译] (21)
- servlet3.x (2)
- websocket协议[翻译] (14)
- websocket规范[翻译] (1)
- java web (6)
- db (1)
- js & jquery & bootstrap (4)
- 非技术 (4)
- reminder[转载] (23)
- 跟叶子学把妹 (8)
- nginx (2)
- 架构 (19)
- flume架构与源码分析 (4)
最新评论
-
xxx不是你可以惹得:
认真看错误代码,有时候重启电脑就行了 醉了 我把数据库配置写死 ...
第十六章 综合实例——《跟我学Shiro》 -
dagger9527:
holyselina 写道您前面说到能获取调用是的参数数组,我 ...
【第六章】 AOP 之 6.6 通知参数 ——跟我学spring3 -
xxx不是你可以惹得:
Access denied for user 'root'@' ...
第十六章 综合实例——《跟我学Shiro》 -
dagger9527:
只有@AspectJ支持命名切入点,而Schema风格不支持命 ...
【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3 -
dagger9527:
支持虽然会迟到,但永远不会缺席!
【第四章】 资源 之 4.3 访问Resource ——跟我学spring3
如何配置mysql数据库的主从?
单机配置mysql主从:http://my.oschina.net/god/blog/496
常见的解决数据库读写分离有两种方案
1、应用层
http://neoremind.net/2011/06/spring实现数据库读写分离
目前的一些解决方案需要在程序中手动指定数据源,比较麻烦,后边我会通过AOP思想来解决这个问题。
2、中间件
mysql-proxy:http://hi.baidu.com/geshuai2008/item/0ded5389c685645f850fab07
Amoeba for MySQL:http://www.iteye.com/topic/188598和http://www.iteye.com/topic/1113437
此处我们介绍一种在应用层的解决方案,通过spring动态数据源和AOP来解决数据库的读写分离。
该方案目前已经在一个互联网项目中使用了,而且可以很好的工作。
该方案目前支持
一读多写;当写时默认读操作到写库、当写时强制读操作到读库。
考虑未来支持
读库负载均衡、读库故障转移等。
使用场景
不想引入中间件,想在应用层解决读写分离,可以考虑这个方案;
建议数据访问层使用jdbc、ibatis,不建议hibernate。
优势
应用层解决,不引入额外中间件;
在应用层支持『当写时默认读操作到写库』,这样如果我们采用这种方案,在写操作后读数据直接从写库拿,不会产生数据复制的延迟问题;
应用层解决读写分离,理论支持任意数据库。
缺点
1、不支持@Transactional注解事务,此方案要求所有读方法必须是read-only=true,因此如果是@Transactional,这样就要求在每一个读方法头上加@Transactional 且readOnly属性=true,相当麻烦。 :oops:
2、必须按照配置约定进行配置,不够灵活。
两种方案
方案1:当只有读操作的时候,直接操作读库(从库);
当在写事务(即写主库)中读时,也是读主库(即参与到主库操作),这样的优势是可以防止写完后可能读不到刚才写的数据;
此方案其实是使用事务传播行为为:SUPPORTS解决的。
方案2:当只有读操作的时候,直接操作读库(从库);
当在写事务(即写主库)中读时,强制走从库,即先暂停写事务,开启读(读从库),然后恢复写事务。
此方案其实是使用事务传播行为为:NOT_SUPPORTS解决的。
核心组件
cn.javass.common.datasource.ReadWriteDataSource:读写分离的动态数据源,类似于AbstractRoutingDataSource,具体参考javadoc;
cn.javass.common.datasource.ReadWriteDataSourceDecision:读写库选择的决策者,具体参考javadoc;
cn.javass.common.datasource.ReadWriteDataSourceProcessor:此类实现了两个职责(为了减少类的数量将两个功能合并到一起了):读/写动态数据库选择处理器、通过AOP切面实现读/写选择,具体参考javadoc。
具体配置
1、数据源配置
1.1、写库配置
<bean id="writeDataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource"> <property name="alias" value="writeDataSource"/> <property name="driver" value="${write.connection.driver_class}" /> <property name="driverUrl" value="${write.connection.url}" /> <property name="user" value="${write.connection.username}" /> <property name="password" value="${write.connection.password}" /> <property name="maximumConnectionCount" value="${write.proxool.maximum.connection.count}"/> <property name="minimumConnectionCount" value="${write.proxool.minimum.connection.count}" /> <property name="statistics" value="${write.proxool.statistics}" /> <property name="simultaneousBuildThrottle" value="${write.proxool.simultaneous.build.throttle}"/> </bean>
1.2、读库配置
<bean id="readDataSource1" class="org.logicalcobwebs.proxool.ProxoolDataSource"> <property name="alias" value="readDataSource"/> <property name="driver" value="${read.connection.driver_class}" /> <property name="driverUrl" value="${read.connection.url}" /> <property name="user" value="${read.connection.username}" /> <property name="password" value="${read.connection.password}" /> <property name="maximumConnectionCount" value="${read.proxool.maximum.connection.count}"/> <property name="minimumConnectionCount" value="${read.proxool.minimum.connection.count}" /> <property name="statistics" value="${read.proxool.statistics}" /> <property name="simultaneousBuildThrottle" value="${read.proxool.simultaneous.build.throttle}"/> </bean>
1.3、读写动态库配置
通过writeDataSource指定写库,通过readDataSourceMap指定从库列表,从库列表默认通过顺序轮询来使用读库,具体参考javadoc;
<bean id="readWriteDataSource" class="cn.javass.common.datasource.ReadWriteDataSource"> <property name="writeDataSource" ref="writeDataSource"/> <property name="readDataSourceMap"> <map> <entry key="readDataSource1" value-ref="readDataSource1"/> <entry key="readDataSource2" value-ref="readDataSource1"/> <entry key="readDataSource3" value-ref="readDataSource1"/> <entry key="readDataSource4" value-ref="readDataSource1"/> </map> </property> </bean>
2、XML事务属性配置
所以读方法必须是read-only(必须,以此来判断是否是读方法)。
<tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="merge*" propagation="REQUIRED" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="put*" read-only="true"/> <tx:method name="query*" read-only="true"/> <tx:method name="use*" read-only="true"/> <tx:method name="get*" read-only="true" /> <tx:method name="count*" read-only="true" /> <tx:method name="find*" read-only="true" /> <tx:method name="list*" read-only="true" /> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
3、事务管理器
事务管理器管理的是readWriteDataSource
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="readWriteDataSource"/> </bean>
4、读/写动态数据库选择处理器
根据之前的txAdvice配置的事务属性决定是读/写,具体参考javadoc;
forceChoiceReadWhenWrite:用于确定在如果目前是写(即开启了事务),下一步如果是读,是直接参与到写库进行读,还是强制从读库读,具体参考javadoc;
<bean id="readWriteDataSourceTransactionProcessor" class="cn.javass.common.datasource.ReadWriteDataSourceProcessor"> <property name="forceChoiceReadWhenWrite" value="false"/> </bean>
5、事务切面和读/写库选择切面
<aop:config expose-proxy="true"> <!-- 只对业务逻辑层实施事务 --> <aop:pointcut id="txPointcut" expression="execution(* cn.javass..service..*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> <!-- 通过AOP切面实现读/写库选择 --> <aop:aspect order="-2147483648" ref="readWriteDataSourceTransactionProcessor"> <aop:around pointcut-ref="txPointcut" method="determineReadOrWriteDB"/> </aop:aspect> </aop:config>
1、事务切面一般横切业务逻辑层;
2、此处我们使用readWriteDataSourceTransactionProcessor的通过AOP切面实现读/写库选择功能,order=Integer.MIN_VALUE(即最高的优先级),从而保证在操作事务之前已经决定了使用读/写库。
6、测试用例
只要配置好事务属性(通过read-only=true指定读方法)即可,其他选择读/写库的操作都交给readWriteDataSourceTransactionProcessor完成。
可以参考附件的:
cn.javass.readwrite.ReadWriteDBTestWithForceChoiceReadOnWriteFalse
cn.javass.readwrite.ReadWriteDBTestWithNoForceChoiceReadOnWriteTrue
可以下载附件的代码进行测试,具体选择主/从可以参考日志输出。
暂不想支持@Transactional注解式事务。
PS:欢迎拍砖指正。
评论
同样这个问题,LZ 是怎么解决的?
解决了 刚才看了下 是因为ShiroFilterFactoryBean也实现了BeanPostProcessor接口 我们只需要自定义数据源的processer再实现Ordered接口,同时指定此接口加载顺序优先shiro就可以了
@Override
public int getOrder() {
return -1;
}
同样这个问题,LZ 是怎么解决的?
请教一个问题,以下场景如何处理?
新增一笔订单(写事务,访问主库),然后页面跳转到订单列表(只读事务,访问从库),如果从库有延迟,就不一定能够显示刚增加的新订单。
我的也是,永远都不会匹配NameMatchTransactionAttributeSource类型,,然后导致读map永远是{}
关于sprng配置动态数据源,我这边遇到一个问题.
我没有用aop来配置哪些方法连写的库,哪些方法连读的库。
我直接是在指定的查询方法里调用ReadWriteDataSourceDecision.markRead()方法,方法执行完之后再调用reset方法。
但是这样会有一个问题,用户并发量大时候,就会有数据源错乱,在写数据库操作的方法里会引用到只读的数据库。
楼主问题下这是什么情况啊?
——估计是WEB服务器都是使用的线程池,有线程变量没清空。
关于sprng配置动态数据源,我这边遇到一个问题.
我没有用aop来配置哪些方法连写的库,哪些方法连读的库。
我直接是在指定的查询方法里调用ReadWriteDataSourceDecision.markRead()方法,方法执行完之后再调用reset方法。
但是这样会有一个问题,用户并发量大时候,就会有数据源错乱,在写数据库操作的方法里会引用到只读的数据库。
楼主问题下这是什么情况啊?
我现在有个问题,就是楼主说不支持@Transactional。我想问一下,假如在方法上面使用了@Transactional并且没有加readonly属性,会有什么情况?是在事务的传播时会有问题吗?
我看楼主通过aop切面来定义事务管理的,假如一个service即满足了aop又满足了@transaction.是不是会开两次事务(spring不太熟,望见凉)
19:46:49.865 [localhost-startStop-1] INFO org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean '(inner bean)#470' of type [class org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
目前确定是与shiro的配置造成的,
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<!-- override these for application-specific URLs if you like:-->
<property name="loginUrl" value="${shiro.login.url}"/>
<property name="unauthorizedUrl" value="${shiro.unauthorizedUrl}"/>
<!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean -->
<!-- defined will be automatically acquired and available via its beanName in chain -->
<!-- definitions, but you can perform instance overrides or name aliases here if you like: -->
<property name="filters">
<util:map>
<entry key="authc" value-ref="formAuthenticationFilter"/>
<entry key="logout" value-ref="logoutFilter"/>
<entry key="sysUser" value-ref="sysUserFilter"/>
<entry key="onlineSession" value-ref="onlineSessionFilter"/>
<entry key="syncOnlineSession" value-ref="syncOnlineSessionFilter"/>
<entry key="jCaptchaValidate" value-ref="jCaptchaValidateFilter"/>
<entry key="develop" value-ref="developFilter"/>
</util:map>
</property>
<property name="filterChainDefinitions">
<value>
/static/** = anon
/anon/** = anon
/login.json = anon
/jcaptcha* = anon
/logout = logout
/login = jCaptchaValidate,authc
/** = develop,sysUser,onlineSession,user,syncOnlineSession,perms,roles
</value>
</property>
</bean>
去掉才可以
19:46:49.865 [localhost-startStop-1] INFO org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean '(inner bean)#470' of type [class org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
管理数据库 manager.db 里面记录每个分公司账册数据库名称
Jiangsu.db
Hunan.db
Zhejiang.db
manager.db中的分账册数据库名是动态的,并不是一个固定记录,我只定义了指向manager.db的
datasource,用于登录是获得各自的数据库名
主要是如何动态的产生到各自数据库的数据源,
我考虑了两个方法
1.通过过滤器+session来实现
2.使用aop,在servise的before中+session来实现,
这些数据库结构一样 系统登录到管理数据库 根据客户端提交的标识 决定客户端登录的默认数据库是那个 但是我不知道这个时候数据源的数据库该如何切换 数据源不是都被在配置文件中定义死了吗。我用spring框架该如何实现。或者有什么变通的办法 后端数据库是sqlserver. 难道只有在操作时都带上库名.
例如
select * from [jiangsu].stock. 查询江苏库存
select * from [zhejiang].stock. 查询浙江库存么
如果可能可以给我个demo,刚刚上手spring, 谢谢
过滤器+ThreadLocal+DynamicDataSource完成:
1、通过过滤器根据用户登录信息选择库 存到ThreadLocal
2、DynamicDataSource通过ThreadLocal选择库
3、退出过滤器时删除ThreadLocal
DynamicDataSource可以搜索下,很多例子
管理数据库 manager.db 里面记录每个分公司账册数据库名称
Jiangsu.db
Hunan.db
Zhejiang.db
manager.db中的分账册数据库名是动态的,并不是一个固定记录,我只定义了指向manager.db的
datasource,用于登录是获得各自的数据库名
主要是如何动态的产生到各自数据库的数据源,
我考虑了两个方法
1.通过过滤器+session来实现
2.使用aop,在servise的before中+session来实现,
这些数据库结构一样 系统登录到管理数据库 根据客户端提交的标识 决定客户端登录的默认数据库是那个 但是我不知道这个时候数据源的数据库该如何切换 数据源不是都被在配置文件中定义死了吗。我用spring框架该如何实现。或者有什么变通的办法 后端数据库是sqlserver. 难道只有在操作时都带上库名.
例如
select * from [jiangsu].stock. 查询江苏库存
select * from [zhejiang].stock. 查询浙江库存么
如果可能可以给我个demo,刚刚上手spring, 谢谢
然后再AOP处理时换成某个读DS,可以避免方法命名约束。。。
根本之道还是根据sql解析得到是什么操作。例如淘宝的tddl
嗯,这个也想到了,但是我觉得如果读方法太多很多的方法头上都有@ReadOnly,不爽 。
发表评论
-
一段Spring代码引起的调用绑定总结
2014-03-04 07:41 15365代码 @Component public class B ... -
一段Spring代码引起的调用绑定总结
2014-03-02 10:53 0代码 @Component public class ... -
Spring Cache抽象详解
2014-01-08 07:54 151068缓存简介 缓存,我的理解是:让数据更接近于使 ... -
Spring3.1新属性管理API:PropertySource、Environment、Profile
2014-01-07 08:05 72967Spring3.1提供了新的属性管理API,而且功能非常强 ... -
Spring3.1新属性管理API:PropertySource、Environment、Profile
2014-01-07 08:04 0Spring3.1提供了新的属性管理API,而且功能非常强 ... -
Spring动态部署Bean/Controller/Groovy Controller
2014-01-06 08:00 24445最近有好几个咨询如何动态部署Bean/动态部署Spring ... -
Spring4新特性——注解、脚本、任务、MVC等其他特性改进
2013-12-25 07:58 68874Spring4新特性——泛型限定式依赖注入 Spring ... -
Spring4新特性——JSR310日期时间API的支持
2013-12-24 07:48 39438Spring4新特性——泛型限定式依赖注入 Spring ... -
Spring3.1新属性管理API:PropertySource、Environment、Profile
2013-12-23 21:44 0Spring3.1提供了新的属性管理API,而且功能非常强 ... -
Spring4新特性——更好的Java泛型操作API
2013-12-23 07:43 41984Spring4新特性——泛型限定式依赖注入 Spring ... -
Spring4新特性——Groovy Bean定义DSL
2013-12-19 07:33 37755Spring4新特性——泛型限定式依赖注入 Spring ... -
Spring4新特性——Groovy Bean定义DSL
2013-12-18 20:53 0Spring4支持使用Groovy DSL来进行Bean定 ... -
Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
2013-12-16 08:10 158094Spring4新特性——泛型限定式依赖注入 Spring ... -
Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC
2013-12-15 10:51 0在之前的《跟我学SpringMVC》中的《第七章 注解式控 ... -
Spring4新特性——Web开发的增强
2013-12-14 08:12 270706Spring4新特性——泛型限定式依赖注入 Spring ... -
Spring4新特性——核心容器的其他改进
2013-12-14 07:23 47738Spring4新特性——泛型限定式依赖注入 Spring ... -
Spring4新特性——核心容器的其他改进
2013-12-13 22:54 311接上一篇《Spring4新特性——泛型限定式依赖注入》,接 ... -
Spring4新特性——泛型限定式依赖注入
2013-12-13 20:46 119547Spring4新特性——泛型限定式依赖注入 Spring ... -
Spring事务超时时间可能存在的错误认识
2013-12-06 09:36 476031、先看代码 1.1、spring-config.xml ... -
采用共享jar包部署struts2+spring集成项目会遇到的问题
2013-11-29 06:45 6348比如tomcat下边有个lib,放着我们需要的struts2 ...
相关推荐
通过以上步骤,你就可以在应用层利用Spring的特性实现数据库读写分离了。在实际项目中,还需要考虑其他的因素,如数据同步(如MySQL的binlog同步)、故障转移、负载均衡等。同时,合理地设计读写策略,避免在高并发...
在应用层解决数据库读写分离可以通过Spring框架来实现,本文将介绍如何使用Spring解决数据库读写分离。 概念 * 读写分离:将数据库的读取和写入操作分开处理,以提高数据库的性能和可用性。 * 主从复制:将主...
通过以上分析,我们可以看出,Spring、Spring MVC、MyBatis和MySQL的组合,为实现数据库读写分离提供了一种高效且灵活的解决方案。理解并掌握这些知识点,对于提升系统的稳定性和性能具有重要的意义。
在IT行业中,数据库读写分离是一种常见的优化策略,特别是在高并发、大数据量的Web应用中。Spring框架结合MyBatis和MySQL数据库,可以方便地实现这一功能。下面将详细讲解如何利用Spring MVC、Spring和MyBatis来实现...
在IT行业中,Spring、SpringMVC和MyBatis是三个非常重要的...同时,通过数据库读写分离,提升了系统的可扩展性和响应速度。对于开发者而言,理解和掌握这些技术能够提升开发效率,构建出高效、稳定的大型分布式应用。
总之,这个"数据库读写分离demo"展示了如何在Java应用中,利用MyBatis和AOP技术来实现数据库读写分离,提高系统的读写性能和稳定性。通过这种方式,我们可以在不影响原有代码结构的前提下,优雅地解决高并发场景下的...
在Spring框架下实现读写分离的核心在于通过AOP(面向切面编程)技术,在调用业务逻辑方法前根据一定的规则(如方法名前缀)来决定使用哪个数据源。具体实现包括以下几个步骤: 1. **定义动态数据源**:继承`...
在现代Web应用开发中,数据库读写分离和缓存技术是提高系统性能和可扩展性的关键策略。本项目采用SpringBoot、MyBatis、Druid和Redis这四个核心技术来实现这一目标。以下将详细讲解这些组件如何协同工作,以及它们...
开发者可以通过学习这个项目,理解如何在实际项目中结合这些技术实现数据库读写分离,提升系统的并发处理能力和稳定性。 总结来说,Spring、SpringMVC、MyBatis和Maven是Java开发中的常见工具,它们共同构建了一个...
本示例"Spring+MySQL+MyBatis+SpringMVC 读写分离"是针对这种策略的一个实现,旨在帮助开发者理解如何在实际项目中应用这一技术。下面将详细介绍这个Demo中的关键知识点。 首先,我们要理解什么是读写分离。读写...
本示例通过Java的面向切面编程(AOP)技术来实现实现MySQL数据库的读写分离,旨在帮助开发者理解如何在实际项目中应用这一技术。 首先,我们要理解什么是AOP(Aspect-Oriented Programming)。AOP是面向切面编程的...
在Java开发领域,数据库读写分离是一种常见的优化策略,它能显著提高系统性能,尤其是在高并发环境下。本项目源码是基于MySQL数据库实现的,利用SSM(Spring、SpringMVC、MyBatis)框架进行开发,旨在帮助开发者快速...
本文将深入探讨如何利用Spring AOP(面向切面编程)实现应用层的MySQL读写分离,并结合一主多从的配置来进行详细讲解。 首先,我们需要理解MySQL的主从复制机制。在主从复制中,数据的写操作(INSERT、UPDATE、...
### Spring 解决读写分离方案详解 #### 一、背景介绍 在现代应用程序开发中,...Spring 的 AOP 特性为我们提供了一个优雅的方式来实现读写分离,尤其适合那些希望在不引入额外中间件的情况下优化数据库性能的项目。
本项目着重于实现数据库的读写分离,以提高系统的性能和可用性。下面我们将详细探讨这个项目中的关键知识点。 1. **Spring框架**:Spring作为核心的依赖注入(DI)和面向切面编程(AOP)框架,提供了一种管理对象...
在IT行业中,数据库读写分离是一种常见的优化策略,特别是在高并发场景下,它能有效提升系统的性能和稳定性。本文将详细讲解如何利用Spring Boot、MyBatis和AOP(面向切面编程)来实现这一技术。 首先,让我们理解...
SpringBoot集成Spring Data JPA及读写分离是现代Java Web应用程序中常见的技术组合,用于高效地管理和处理数据库操作。Spring Boot简化了应用的初始化和配置,而Spring Data JPA则进一步降低了使用Java Persistence ...
在现代的高并发Web应用中,数据库的读写分离是一种常见的优化策略,它可以提高系统的并发处理能力和稳定性。本文将深入探讨如何使用SpringMVC和MyBatis框架来实现读写分离,尤其是“一写多读”的模式。我们将讨论...
在构建高性能的企业级应用时,数据库读写分离和多数据源配置是常见的优化策略,能够有效地提高系统的可扩展性和稳定性。本篇文章将详细介绍如何利用Spring和Mybatis框架实现这一目标。 首先,数据库读写分离的基本...