返回顶部
首页 > 资讯 > 后端开发 > Python >ShardingJdbc读写分离的BUG踩坑解决
  • 941
分享到

ShardingJdbc读写分离的BUG踩坑解决

2024-04-02 19:04:59 941人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录前言数据库介绍1. 常规写完读2. 在一个 service 里面调用另一个 service3. 新开一个线程去调用 service24. service2 新开一个事务执行前言

前言

最近公司准备接入ShardingJdbc做读写分离了,老大让我们理一理有没有写完数据立马读的场景,因为主从同步是有延迟的,如果写完读取数据走到从库,而从库正好有延迟,没读取到数据,岂不是造成了生产事故。

今天我们来看看,ShardingJdbc作为一个成熟的框架是怎么处理写完数据立即读取的场景的。

数据库介绍

我本地使用了两个库来做实验,写库(ds_0_master)和读库(ds_0_salve),两个库并没有配置主从,但也不影响实验操作。

库里有一个city 表。主库的 city 表没有数据,而从库的 city 表就一条数据。数据内容如下:

我们讨论 4 种业务场景:

  • 常规写完读
  • 在一个 service 里面调用另一个 service2 进行读
  • 在一个 service 里面新开一个线程去调用 service2
  • 在一个 service 里面调用 service2,但 service2 是新开的事务

先直接上实验结果:

1. 常规写完读

@Service
public class CityService {
    @Autowired
    private CityRepository cityRepository;
    @Autowired
    private CityService2 cityService2;
    @Transactional(rollbackFor = Exception.class)
    public void test(){
        City city=new City();
        city.setName("眉山");
        city.setProvince("四川");
        cityRepository.save(city);
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.out.println("cityService:"+((x.getProvince().equals("四川"))?"主库":"从库")+":"+x);
        });
    }
}

打印结果:

实验分析: 我们对 city 表进行插入后,紧接着对 city 表进行了查询,查出的内容是我们刚刚插入的内容。说明查询操作没有走读库,而是走了主库。

2. 在一个 service 里面调用另一个 service

代码如下:

 @Transactional(rollbackFor = Exception.class)
    public void test(){
        City city=new City();
        city.setName("眉山");
        city.setProvince("四川");
        cityRepository.save(city);
        //调用其他service
        cityService2.test();
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.out.println("cityService:"+((x.getProvince().equals("四川"))?"主库":"从库")+":"+x);
        });
    }
}

service2 的代码:

public void test(){
    List<City> all = cityRepository.findAll();
    all.forEach(x->{
        System.err.println("cityService2:"+((x.getProvince().equals("四川"))?"主库":"从库")+":"+x);
    });
}

打印结果:

实验分析:在 service 方法里调用了其他 service,其他 service 也会受到影响。service2 也是走的主库。

3. 新开一个线程去调用 service2

代码如下:

@Service
public class CityService {
    @Autowired
    private CityRepository cityRepository;
    @Autowired
    private CityService2 cityService2;
    @Transactional(rollbackFor = Exception.class)
    public void test(){
        City city=new City();
        city.setName("眉山");
        city.setProvince("四川");
        cityRepository.save(city);
        new Thread(()->{cityService2.test();}).start();
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.out.println("cityService:"+((x.getProvince().equals("四川"))?"主库":"从库")+":"+x);
        });
    }
}
@Service
public class CityService2 {
    @Autowired
    private CityRepository cityRepository;
    public void test(){
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.err.println("cityService2:"+((x.getProvince().equals("四川"))?"主库":"从库")+":"+x);
        });
    }
}

打印结果:

实验分析: 我们新开了线程对 city 表进行查询,此次查询读的是从库。新开的线程会走从库,我猜想是新开的线程它认为是没有写入/修改操作,所以走了从库。

我又改动了 service2,加了一段写入操作。代码如下:

    public void test(){
        City city=new City();
        city.setName("成都");
        city.setProvince("四川");
        cityRepository.save(city);
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.err.println("cityService2:"+((x.getProvince().equals("四川"))?"主库":"从库")+":"+x);
        });
    }

再次执行,结果如下:

和预想的不一样,依旧是走的从库。

4. service2 新开一个事务执行

我们调整 service2 的事务传播行为级别。代码如下:

@Transactional(propagation = Propagation.REQUIRES_NEW)
    public void test(){
        List<City> all = cityRepository.findAll();
        all.forEach(x->{
            System.err.println("cityService2:"+((x.getProvince().equals("四川"))?"主库":"从库")+":"+x);
        });
    }

REQUIRES_NEW 的含义是:

强制自己开启一个新的事务,如果一个事务已经存在,那么将这个事务挂起.如 ServiceA.methodA()调用 ServiceB.methodB(),methodB()上的传播级别是 PROPAGATION_REQUIRES_NEW 的话,那么如果 methodA 报错,不影响 methodB 的事务,如果 methodB 报错,那么 methodA 是可以选择是回滚或者提交的,就看你是否将 methodB 报的错误抛出还是 try catch 了.

打印结果:

实验分析: 这个结果确实是没想到,service2 新开了个事务走的是主库,而 service 里面的同一个事务里的写后读,反而走了从库。

实验总结:

场景serviceservice2
同一个 service 里写完读主库主库
service 里写完调用另一个 servcie 进行读操作主库主库
service 里写完新开线程调用另一个 servcie 进行读操作主库从库
service 里写完新开一个事务调用另一个 servcie 进行读操作从库主库

常规的写完读操作和写完在另一个 service 里进行读操作,都能够走到主库,保证了常规业务的正确性,也满足了我们一般的使用场景了。而新开线程进行读操作的情况其实比较少,如果非要使用,我们可以用强制指定主库的方式进行处理。

最后一种情况,service中调用另一个service2(新开事务),原本 service 里同一个事务的写完读操作走到了从库,一不注意容易引起实际业务bug,需要使用者谨慎使用。大家觉得这是不是ShardingJdbc的一个BUG呢?

以上就是ShardingJdbc读写分离的BUG踩坑解决的详细内容,更多关于ShardingJdbc读写分离BUG的资料请关注编程网其它相关文章!

--结束END--

本文标题: ShardingJdbc读写分离的BUG踩坑解决

本文链接: https://lsjlt.com/news/166246.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • ShardingJdbc读写分离的BUG踩坑解决
    目录前言数据库介绍1. 常规写完读2. 在一个 service 里面调用另一个 service3. 新开一个线程去调用 service24. service2 新开一个事务执行前言 ...
    99+
    2024-04-02
  • 数据库读写分离的坑有哪些
    这篇文章主要讲解了“数据库读写分离的坑有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“数据库读写分离的坑有哪些”吧!前言事情是这样的,刚入职的时候接到了...
    99+
    2024-04-02
  • MySQL读写分离写完读不到问题如何解决
    本篇内容介绍了“MySQL读写分离写完读不到问题如何解决”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!今天...
    99+
    2024-04-02
  • 解决Go gorm踩过的坑
    使用gorm.Model后无法查询数据 Scan error on column index 1, name “created_at” 提示: Scan error on...
    99+
    2022-06-07
    gorm GO
  • SpringBootTest--踩坑错误的解决
    目录SpringBootTest 踩坑SpringBootTest的一个小坑注意点1、我当时运行SpringBoot测试类的时候踩这个坑2、解决方法SpringBootTest 踩坑...
    99+
    2024-04-02
  • 怎么理解Mycat读写分离
    这篇文章主要介绍“怎么理解Mycat读写分离”,在日常操作中,相信很多人在怎么理解Mycat读写分离问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么理解Mycat读写分离”...
    99+
    2024-04-02
  • Mysql读写分离过期常用解决方案
    mysql读写分离的坑 读写分离的主要目标是分摊主库的压力,由客户端选择后端数据库进行查询。还有种架构就是在MYSQL和客户端之间有一个中间代理层proxy,客户端之连接proxy,由proxy根据请求类型和上下文...
    99+
    2022-05-17
    Mysql 读写 分离
  • mycat做Mysql的读写分离
    在MySQL中间件出现之前,对于MySQL主从集群,如果要实现其读写分离,一般是在程序端实现,这样就带来一个问题,即数据库和程序的耦合度太高,如果我数据库的地址发生改变了,那么我程序端也要进行相应的修改,如...
    99+
    2024-04-02
  • 数据库的读写分离能解决什么问题
    数据库的读写分离能解决什么问题,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。有一些技术同学可能对于“读写分离”了解不多,认为数...
    99+
    2024-04-02
  • 解决springCache配置中踩的坑
    目录springCache配置中踩的坑先附上正确的配置springCache配置及一些问题的解决配置@Cacheable参数@CacheEvict 参数@CachePut 参数spr...
    99+
    2024-04-02
  • MyCAT实现MySQL的读写分离
    在MySQL中间件出现之前,对于MySQL主从集群,如果要实现其读写分离,一般是在程序端实现,这样就带来一个问题,即数据库和程序的耦合度太高,如果我数据库的地址发生改变了,那么我程序端也要进行相应的修改,如...
    99+
    2024-04-02
  • amoeba:关于mysql的读写分离
    今天用amoeba做了次读写分离,下面总结下步骤:三台linux:1、192.168.1.213    用于做amoeba服务器2、192.168.1.184&nbs...
    99+
    2024-04-02
  • 详解JavaScheduledThreadPoolExecutor的踩坑与解决方法
    目录概述还原"大坑"解决方案更推荐的做法原理探究总结概述 最近项目上反馈某个重要的定时任务突然不执行了,很头疼,开发环境和测试环境都没有出现过这个问题。定时任务采...
    99+
    2022-11-13
    Java ScheduledThreadPoolExecutor
  • 解决spring集成redisson踩过的坑
    目录spring集成redisson踩过的坑第一坑就是版本兼容问题第二个坑是设置密码问题spring整合redisson配置配置方式单节点配置standalone哨兵配置sentin...
    99+
    2024-04-02
  • springboot整合freemarker的踩坑及解决
    目录springboot整合freemarker踩坑报错问题原因解决方法springboot freemarker基础配置及使用1.基础配置2.基础使用springboot整合fre...
    99+
    2024-04-02
  • 如何解决Go gorm踩过的坑
    这篇文章给大家分享的是有关如何解决Go gorm踩过的坑的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。什么是gogo是golang的简称,golang 是Google开发的一种静态强类型、编译型、并发型,并具有垃...
    99+
    2023-06-14
  • Tauri 打开本地文件踩坑分析解决
    目录Tauri 打开本地文件踩坑需求<input type="file" >存在的问题Dialog打开文件fs读取文件最终解决办法Tauri 打开本地...
    99+
    2023-05-16
    Tauri 打开本地文件踩坑 Tauri 打开本地文件
  • vue3 pinia踩坑及解决实例代码分析
    本篇内容主要讲解“vue3 pinia踩坑及解决实例代码分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue3 pinia踩坑及解决实例代码分析”吧!安装yarn&nbs...
    99+
    2023-07-05
  • 使用Spring AOP切面解决数据库读写分离
    概要:为了减轻数据库的压力,一般会使用数据库主从(master/slave)的方式,但是这种方式会给应用程序带来一定的麻烦,比如说,应用程序如何做到把数据写到master库,而读取数据的时候,从slave库...
    99+
    2024-04-02
  • MySQL主从延迟、读写分离问题如何解决
    本文小编为大家详细介绍“MySQL主从延迟、读写分离问题如何解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“MySQL主从延迟、读写分离问题如何解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作