如何在应用层通过spring特性解决数据库读写分离

如何在应用层通过spring特性解决数据库读写分离,第1张

两种方案

方案1:当只有读 *** 作的时候,直接 *** 作读库(从库);

当在写事务(即写主库)中读时,也是读主库(即参与到主库 *** 作),这样的优势是可以防止写完后可能读不到刚才写的数据;

此方案其实是使用事务传播行为为:SUPPORTS解决的。

方案2:当只有读 *** 作的时候,直接 *** 作读库(从库);

当在写事务(即写主库)中读时,强制走从库,即先暂停写事务,开启读(读从库),然后恢复写事务。

此方案其实是使用事务传播行为为:NOT_SUPPORTS解决的。

核心组件

cnjavasscommondatasourceReadWriteDataSource:读写分离的动态数据源,类似于AbstractRoutingDataSource,具体参考javadoc;

cnjavasscommondatasourceReadWriteDataSourceDecision:读写库选择的决策者,具体参考javadoc;

cnjavasscommondatasourceReadWriteDataSourceProcessor:此类实现了两个职责(为了减少类的数量将两个功能合并到一起了):读/写动态数据库选择处理器、通过AOP切面实现读/写选择,具体参考javadoc。

具体配置

1、数据源配置

11、写库配置

Java代码

<bean id="writeDataSource" class="orglogicalcobwebsproxoolProxoolDataSource">

<property name="alias" value="writeDataSource"/>

<property name="driver" value="${writeconnectiondriver_class}" />

<property name="driverUrl" value="${writeconnectionurl}" />

<property name="user" value="${writeconnectionusername}" />

<property name="password" value="${writeconnectionpassword}" />

<property name="maximumConnectionCount" value="${writeproxoolmaximumconnectioncount}"/>

<property name="minimumConnectionCount" value="${writeproxoolminimumconnectioncount}" />

<property name="statistics" value="${writeproxoolstatistics}" />

<property name="simultaneousBuildThrottle" value="${writeproxoolsimultaneousbuildthrottle}"/>

</bean>

12、读库配置

Java代码

<bean id="readDataSource1" class="orglogicalcobwebsproxoolProxoolDataSource">

<property name="alias" value="readDataSource"/>

<property name="driver" value="${readconnectiondriver_class}" />

<property name="driverUrl" value="${readconnectionurl}" />

<property name="user" value="${readconnectionusername}" />

<property name="password" value="${readconnectionpassword}" />

<property name="maximumConnectionCount" value="${readproxoolmaximumconnectioncount}"/>

<property name="minimumConnectionCount" value="${readproxoolminimumconnectioncount}" />

<property name="statistics" value="${readproxoolstatistics}" />

<property name="simultaneousBuildThrottle" value="${readproxoolsimultaneousbuildthrottle}"/>

</bean>

13、读写动态库配置

通过writeDataSource指定写库,通过readDataSourceMap指定从库列表,从库列表默认通过顺序轮询来使用读库,具体参考javadoc;

Java代码

<bean id="readWriteDataSource" class="cnjavasscommondatasourceReadWriteDataSource">

<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(必须,以此来判断是否是读方法)。

Java代码

<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

Java代码

<bean id="txManager" class="orgspringframeworkjdbcdatasourceDataSourceTransactionManager">

<property name="dataSource" ref="readWriteDataSource"/>

</bean>

4、读/写动态数据库选择处理器

根据之前的txAdvice配置的事务属性决定是读/写,具体参考javadoc;

forceChoiceReadWhenWrite:用于确定在如果目前是写(即开启了事务),下一步如果是读,是直接参与到写库进行读,还是强制从读库读,具体参考javadoc;

Java代码

<bean id="readWriteDataSourceTransactionProcessor" class="cnjavasscommondatasourceReadWriteDataSourceProcessor">

<property name="forceChoiceReadWhenWrite" value="false"/>

</bean>

5、事务切面和读/写库选择切面

Java代码

<aop:config expose-proxy="true">

<!-- 只对业务逻辑层实施事务 -->

<aop:pointcut id="txPointcut" expression="execution( cnjavassservice())" />

<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=IntegerMIN_VALUE(即最高的优先级),从而保证在 *** 作事务之前已经决定了使用读/写库。

6、测试用例

只要配置好事务属性(通过read-only=true指定读方法)即可,其他选择读/写库的 *** 作都交给readWriteDataSourceTransactionProcessor完成。

可以参考附件的:

cnjavassreadwriteReadWriteDBTestWithForceChoiceReadOnWriteFalse

cnjavassreadwriteReadWriteDBTestWithNoForceChoiceReadOnWriteTrue

可以下载附件的代码进行测试,具体选择主/从可以参考日志输出。

通常读 *** 作要比写 *** 作的数量多得多,而且数据库在数据写入时是会锁表的,这个过程不能读取数据,必须等待写入完成,所以一旦请求量大那么执行效率就降低了。读写分离就是一个库只负责读取不做写入,这样就提高了读的效率。

一般都会以oracle DG的方式实现,主库主要就是写入数据,然后通过日志抄送的方式到备库,然后备库以只读模式打开。不过备用库以只读模式打开对数据库的版本有要求,好像低版本的数据库没有这个功能。

以上就是关于如何在应用层通过spring特性解决数据库读写分离全部的内容,包括:如何在应用层通过spring特性解决数据库读写分离、为什么数据库读写分离可以提高性能、如何实现Oracle数据库的读写分离等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/9817282.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-02
下一篇 2023-05-02

发表评论

登录后才能评论

评论列表(0条)

保存