当读写分离遇到事务

7ea4485ad42699796f5820069076eada.jpeg

为了避免频繁创建构造成本大的对象,我们会选择使用线程池、连接池这类池化技术来复用对象。复用对象意味着可能在共享一个资源,如果前一个使用者使用完没有将对象属性值重置为初始状态的话,数据就错乱了。池化技术还有一种隐患,异常没有得到妥善处理,归还的对象就不能复用,池中的可用对象很快就会耗尽,最终由于资源限制无法创建新对象,这个池子就会拒绝服务。

工作中,为了减轻数据库主库压力,通常都进行读写分离。不过,当读写分离遇到数据库连接池时,处理不当就有可能出现异常,比如读操作正常在从库上执行,写操作却也跟过来了。

读写分离实现有很多种方案,一般是通过配置数据库注解切面拦截,不同的注解使用不同的数据源。或者,通过持久化组件的插件,识别方法名前缀来决定要不要使用从库。这样就可以实现动态数据源。

说到注解啊,不知道你习惯在持久化Dao层,还是在服务Service层使用缓存、数据库、事务这些注解呢?这个关乎着注解路径扫描、架构分层。我见过很多在持久化Dao层大量使用缓存注解的情况,在架构演进过程中,数据库操作被其他服务给代替了,不得不花费人力把操作缓存和操作数据库分离,它们两个原本就不应该耦合。

刚刚说到的动态数据源,背后的技术是线程局部变量ThreadLocal,它允许我们在线程周期内直接使用存储的变量,避免到处构建,减少了复杂度。不过,周期结束前没有清空的话,新的请求就会看到上一个请求的数据。多线程下使用ThreadLocal也是会有这种问题的。这就是为什么读写分离遇到连接池、事务容易出现问题的原因。

还有一种操作也会引起错乱。一个读接口和一个写接口,只有读接口的方法标注了需要使用从库,而写接口的方法上没有标注,其中某读方法内部调用了写方法,这样即使有默认配置也会错乱的。我们得在写接口的方法也标注上才行。

那当读写分离遇到事务时,怎么优雅处理呢?

我觉得,很多场景其实不需要事务的,我们人为地把架构搞复杂了。比如,我们可以这样做,先写副表再写主表,副表失败了顶多是脏数据,用户重试后不出意外都会恢复的。有时让用户重试比很多复杂方案都靠谱。如果一定要用事务,那就得小心处理数据源使用善后的问题。

总结来说,读写分离遇到连接池和事务都是有一些坑的,所以一般在非关键业务才采用读写分离,这样也不用考虑写完立即读时主从复制延迟大怎么办。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值