最近莫名的会有错误日志,说有写操作因为走了读库而报了read only的异常,由于并没有造成应用使用的问题,开始我以为哪的配置错误就没当回事让程序员自己去查了,然而。。。

  背景:之前的博客里提到过,读写分离功能是直接从老系统迁移过来的,老系统可能是因为主从库之间同步延迟而使用了基于请求层面的读写分离,迁过来的时候降成了基于Service,新系统用了dubbox,这些Service直接充当Provider。读写分离的实现是重写了了DataSource,请求到Service的时候会先经过拦截器判断方法是走读库还是写库,默认是写库,如果是要走读库的会用ThreadLocal标记为读,否则标记为写。由于读压力远高于写,所以并不是所有读都走写库,避免两个数据库压力不均,通过人为指定来平衡两个库的压力,也就是说是以标记为准而不是以请求类型为准。

  从第一截图可以看到,当遇到没有被标记的事务获取数据源的时候,默认会设置为写。原本这其实是没有什么问题的,因为需要走到写库的都会先被拦截器拦截标记为写:

  而这个determineCurrentLookupKey就是我们重写的方法,也就是上面的第一个截图,所以貌似看上去没什么问题。因为一个事务被设置一个数据源,即使请求因为线程池被复用的关系,上一次请求的ThreadLocal没有专门清理,在新的请求进来的时候这个值也会被拦截器更新。而且,嵌套事务中每个子事务都会保存一个自己的状态,子事务执行完回将状态重置回它开始时候得状态(这个状态也是通过ThreadLocal保存的):

  数据源与连接的绑定关系也是通过ThreadLocal保存的,因为一个事务也只能使用一个连接,所以将唯一的数据源(即使可能不确定)与连接绑定也没什么关系,反正事务结束后会清理掉。

  本来如果维持这个事务体系的闭环就好了,然而依然是因为determineCurrentLookupKey被重写的原因,begin时候数据源的状态对Spring的事务体系就不可见了,是运行时动态选择的,而这个状态的选择在一般情况下依赖于拦截器。为什么说是一般情况下呢,因为有特殊情况会出现,比如第一个图中的=null,只要拦截器先执行了就不会出现=null的情况,问题就出现在先执行上。如果TransactionInterceptor先执行,这里就没有依赖于拦截器,刚才一直都在重点说ThreadLocal,如果这个线程刚巧在上一个事务中把第二个图中的holder设为了读,一连串的问题就来了,首先外层事务的状态就不对了,又因为各个嵌套的子事务的的状态都是隔离的,即使后续子事务的启动是在外层方法被拦截之后得到了正确的连接,但是由于一个事务只有有一个连接,ThreadLocal中已经保存的有数据源和连接了,所以每个事务的状态可能是对的,但提交时用的也就是上图中的连接时错的,本来应该是指向写库的就变成读库了,提交就是用的读库的连接进行的。

  找到问题,解决就容易了,只要设置一下拦截器的执行顺序就好了;也可以通过在提交事务后清理我们自己的ThreadLocal来解决,只需要继承DataSourceTransactionManager重写其中比如清理方法就可以了。

==========================================================

咱最近用的github:https://github.com/saaavsaaa

微信公众号:

                      

使用ThreadLocal实现的读写分离在迁移后的偶发错误的更多相关文章

  1. Hishop网站迁移后出现DataProtectionConfigurationProvider错误

    错误代码如下: 配置错误 说明: 在处理向该请求提供服务所需的配置文件时出错.请检查下面的特定错误详细信息并适当地修改配置文件. 分析器错误信息: 未能使用提供程序“DataProtectionCon ...

  2. hishop网站迁移后出现DataProtectionConfigurationProvider错误(转)

    配置错误说明: 在处理向该请求提供服务所需的配置文件时出错.请检查下面的特定错误详细信息并适当地修改配置文件.分析器错误信息: 未能使用提供程序“DataProtectionConfiguration ...

  3. 【转】双机高可用、负载均衡、MySQL(读写分离、主从自动切换)架构设计

    架构简介 前几天网友来信说帮忙实现这样一个架构:只有两台机器,需要实现其中一台死机之后另一台能接管这台机器的服务,并且在两台机器正常服务时,两台机器都能用上.于是设计了如下的架构.此架构主要是由kee ...

  4. linux安装redis及主从复制、读写分离、哨兵模式

    Redis安装与部署 版本最好选择3.0及以上.以后还可以部署Redis集群. 1.下载: [root@bogon redis-3.0.0]# cd /usr/local [root@bogon lo ...

  5. MHA+ProxySQL 读写分离高可用

    文档结构如下: 1.ProxySQL说明 ProxySQL是mysql的一款中间件的产品,是灵活的mysql代理层,可以实现读写分离,支持query路由器的功能,支持动态指定sql进行缓存,支持动态加 ...

  6. 重要参考步骤---ProxySQL实现读写分离

    MySQL配置主从同步文章地址:https://www.cnblogs.com/sanduzxcvbnm/p/16295369.html ProxySQL实现读写分离与读负载均衡参考文档:https: ...

  7. mybatis plugins实现项目【全局】读写分离

    在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...

  8. J2EE 项目读写分离

    先回答下 1.为啥要读写分离? 大家都知道最初开始,一个项目对应一个数据库,基本是一对一的,但是由于后来用户及数据还有访问的急剧增多, 系统在数据的读写上出现了瓶颈,为了让提高效率,想读和写不相互影响 ...

  9. Spring 实现数据库读写分离

    随着互联网的大型网站系统访问量的增高,数据库访问压力方面不断的显现而出,所以许多公司在数据库层面采用读写分离技术,也就是一个master,多个slave.master负责数据的实时更新或实时查询,而s ...

随机推荐

  1. JavaWeb总结(二)—HttpServletResponse对象

    Web服务器收到客户端的http请求,会针对每一次的请求,分别创建一个用于代表请求的request对象和response对象.我们要获取客户端提交的数据,只需要找request对象.要向客户端输出数据 ...

  2. MySQL数据库的安装布局

    首先我们要安装(mysql-5.0.18-win32_zip) 第一步:点击(Setup.exe) 第二步:开始安装(MySQL Server5.0版本) 1.点击(Next) 2.选Custom自定 ...

  3. netty——私有协议栈开发案例

    netty--私有协议栈开发案例 摘要: 在学习李林峰老师的Netty权威指南中,觉得第十二章<私有协议栈开发>中的案例代码比较有代表性,讲的也不错,但是代码中个人认为有些简单的错误,个人 ...

  4. Vue 事件驱动和依赖追踪

    之前关于 Vue 数据绑定原理的一点分析,最近需要回顾,就顺便发到随笔上了 在之前实现一个自己的Mvvm中,用 setter 来观测model,将界面上所有的 viewModel 绑定到 model ...

  5. 点击按钮,缩放图片(img.width、img.style.width、img.offsetWidth)

    前几天在慕课网上看到一个关于图片缩放的教学视频,因为当时对老师使用img.width,而不是使用img.style.width而感到奇怪,所以周末得空了,想来自己试着写出来,相关视频网址如下:http ...

  6. java进制转换(无视正负数的差别)

    最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤其是对于负数这一方面. 下面和大家分享一下,这里只写了十进制到二进制的转换,其实都是同样的道理 public class Test1 { pub ...

  7. C语言的一些基础

    一.C语言基础: 1.1.main函数是入口函数,用于进行link. 1.2..sln是解决方案的管理文件. 1.3.int:32位.short:16位.long:32位.long long:64位. ...

  8. ORA-01034: ORACLE not available ORA-27101: shared memory realm does not exist

    Oracle 设置默认数据库 如果我们的服务器上或者电脑上安装了多个数据库,当我们使用sqlplus时如果为指定数据库时登录到的是哪一个数据库呢?今天遇到了一个老问题: ORA-01034: ORAC ...

  9. 安卓手机免root实现对其他软件最高管理(sandbox思想)

      root之后的安卓系统并不稳定,root后有时候会出现一些系统的错误,如果实在忍受不了的话,这时候只能恢复出厂设置了.因此不root是最优的选择,但是不root情况下,并没有哪个软件可以实现对其它 ...

  10. 手把手教你学SVN

    注意 转载须保留原文链接(http://www.cnblogs.com/wzhiq896/p/6822713.html  ) 作者:wangwen896 整理 对于很多新手来说,SVN 代码托管一无所 ...