ShardingJdbc 怎么处理写完数据立即读的情况的呢?

写在前面

我本地使用了两个库来做写库(ds_0_master)和读库(ds_0_salve),两个库并没有配置主从。

下面我就使用库里的 city 表做实验。主库的 city 表没有数据,而从库的 city 表就一条数据

我们讨论 4 种情况:

  1. 常规写完读
  2. 在一个 service 里面调用另一个 service2 进行读
  3. 在一个 service 里面新开一个线程去调用 service2
  4. 在一个 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 里面的同一个事务里的写后读,反而走了从库。

实验总结:

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

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

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

踩坑,发现一个ShardingJdbc读写分离的BUG的更多相关文章

  1. SpringBoot使用Sharding-JDBC读写分离

    本文介绍SpringBoot使用当当Sharding-JDBC进行读写分离. 1.有关Sharding-JDBC 本文还是基于当当网Sharding-Jdbc的依赖,与上一篇使用Sharding-Jd ...

  2. Spring Boot中整合Sharding-JDBC读写分离示例

    在我<Spring Cloud微服务-全栈技术与案例解析>书中,第18章节分库分表解决方案里有对Sharding-JDBC的使用进行详细的讲解. 之前是通过XML方式来配置数据源,读写分离 ...

  3. Spring Boot + Sharding-JDBC 读写分离

    本文使用 Sharding-JDBC 实现读写分离,基于 CentOS 7 + MySQL 5.7 一.MySQL 安装及配置 1.1 安装 依次执行命令: sudo wget -i -c http: ...

  4. 我通过调试ConcurrentLinkedQueue发现一个IDEA的小虫子(bug), vscode复现, eclipse毫无问题

    前言: 本渣渣想分析分析Doug Lea大佬对高并发代码编写思路, 于是找到了我们今天的小主角ConcurrentLinkedQueue进行鞭打, 说实话草稿我都打好了, 就差临门一脚, 给踢折了 直 ...

  5. Sharding-JDBC读写分离

    https://www.jianshu.com/p/8bbc8ca63037 官网文档:当当网,架构师张亮 http://shardingsphere.io/document/current/cn/m ...

  6. 发现一个c++ vector sort的bug

    在开发中遇到一个非常诡异的问题:我用vector存储了一组数据,然后调用sort方法,利用自定义的排序函数进行排序,但是一直都会段错误,在排序函数中打印参加排序的值,发现有空值,而且每次都跟同一个数据 ...

  7. 我的踩坑之旅-跨域问题引发bug

    场景: 由于业务原因需要在请求中添加一个信息表明请求的source,经过一轮方案的评审,大家共同决定把这source信息存放在消息header中.前端小伙伴听完之后心里暗自偷笑:就一行的代码的事,请求 ...

  8. 我的踩坑之旅-代码不规范引发的“bug”

    今早公司上班,老大跟我说有一个服务老是上线,下线,问我啥情况.我回想了下我的项目部署,觉得不可能会出现这个问题呀.然后各种鼓捣,倒腾了一个早上,终于找出了罪魁祸首. 场景:我们的服务部署在亚马逊上.我 ...

  9. vue+ vue-router + webpack 踩坑之旅

    说是踩坑之旅 其实是最近在思考一些问题 然后想实现方案的时候,就慢慢的查到这些方案   老司机可以忽略下面的内容了 1)起因  考虑到数据分离的问题  因为server是express搭的   自然少 ...

随机推荐

  1. TypeScript(3)基础类型

    基础类型 TypeScript 支持与 JavaScript 几乎相同的数据类型,此外还提供了实用的枚举类型方便我们使用. 布尔值 最基本的数据类型就是简单的true/false值,在JavaScri ...

  2. H2-Table CATALOGS not found

    在使用 IntelliJ IDEA 2021.1.3 版本,使用默认配置连接 H2 数据库的时候,出现下面错误,项目里 H2 使用的版本为 2.0.202 . [42S02][42102] org.h ...

  3. nginx https证书配置

    1. Nginx配置 server { listen 443; #指定ssl监听端口 server_name www.example.com; ssl on; #开启ssl支持 ssl_certifi ...

  4. BUUCTF-签到题

    签到题 很简单写在介绍里面了.

  5. 手把手教学~基于element封装tree树状下拉框

    在日常项目开发中,树状下拉框的需求还是比较常见的,但是element并没有这种组件以供使用.在这里,小编就基于element如何封装一个树状下拉框做个详细的介绍. 通过这篇文章,你可以了解学习到一个树 ...

  6. SAP APO-供需匹配

    供需匹配包含主要功能"匹配能力"(CTM)和一个用于分配库存的附加功能. 在高级计划和优化中,SDM组件为这些应用程序提供跨工厂供应策略- 生产计划和详细计划(PP / DS) 供 ...

  7. WPF开发随笔收录-唯一标识符GUID

    一.前言 该系列博客用于记录本人在WPF开发过程中遇到的各种知识点 二.正文 1.在工作的项目中,软件需要用到在线升级功能,由于第一次弄,在下载服务端的文件到本地时,文件的名称我选择直接生成为固定的格 ...

  8. oracle备份数据库数据及导入数据库

    1.oracle数据库备份和导入 bat 脚本 scott oracle数据库用户名称 123456 数据库scott用户下的密码 192.168.124.8 本电脑IP orcl 为oracle库 ...

  9. NC16663 [NOIP2004]合并果子

    NC16663 [NOIP2004]合并果子 题目 题目描述 ​ 在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆. ​ 每一次合并,多多可 ...

  10. 正睿七连测 DAY5 T2

    题是水题,也不难想,本来是想打暴力先过个小数据, 本来就想再搞搞优化试试能不能过,毕竟这个题理论上 O( $n^2$ ) 是能过的 题干 主要是觉得这个优化很有可取之处,本来超时,一加这个优化就好很多 ...