java web应用中,最先遇到性能瓶颈的就是数据库了。对于解决这个性能问题,首选方案就是数据库的读写分离。这里不谈如何构建数据库的数据同步,想谈的是当我们有了数据库的读库与写库如何进行读写分离。如果数据库本身就提供读写分离,或者说数据库本身支持读写分离,那么对于用户来说那是再好不过了,比如oracle rac就可以。另外还有mysql replication 驱动,当然它需要与应用事务结合。
在此想说的是我们如何在应用系统层面来解决数据库读写分离?换个角度思考一下,如果我们能够解决这个问题,那么后面的问题就是数据库之间的同步复制,这两个问题结合就是完整的数据库读写分离方案。期望在应用系统层面解决数据库的读写分离,为是让整个解决方案简单,况且这个解决方案放之四海而皆准。
在java web应用,我们解决事务,基本均是应用spring的声明式事务管理方式进行切面增强service层方法来解决。即事务解决方式均是采用类似如下方式:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes> <tx:method name="do*" read-only="false" rollback-for="Exception" /> <tx:method name="is*" read-only="true" /> <tx:method name="has*" read-only="true" /> <tx:method name="query*" read-only="true" /> </tx:attributes> </tx:advice> <aop:config proxy-target-class="true"> <aop:advisor pointcut="execution(* com.test.service.support.*Impl.*(..))) " advice-ref="txAdvice" /> </aop:config>基于这个思路,可以将方法分为两类,需要事务的与不需要事务的。需要事务的则走主库,而不需要事务的则走从库。然而这个思路一般情况下并不可行,原因是事务管理一般情况下都是托管给后端的数据库,或者说spring本身并不具有事务管理的功能,它只一个托,而具体的事务管理还是由后端的数据库来承担。说的再直白点就是transactionManager实例需要dataSource,也就是说先有dataSource实例才能实例化transactionManager(但这不是绝对的比如jta事务,但是对于上面的配置是这样的)。
但这并不妨碍我们沿着这个思路往下思考,如果应用系统在进行方法调用时,能够知道该方法需要事务则我们将让它走主库,否则就让其走从库。那么我们如何让应用系统知道这个信息呢?这就是切面的功劳了。基于以上思路,我在github coding一段代码db-loadbalance,算是对于这个整体思路的总结。具体地址为:https://github.com/zhuzhong/db-loadbalance
以上的代码已被我删除,请参见另外一个项目 https://github.com/zhuzhong/DB-masterslave.git