1、最开始问题
2、找到接口,debug调试,最终确定哪个方法出现问题
3、最开始怀疑问题原因,是并发导致的bug
经过多次调试,不是这个问题,安卓在开启直播时会连续调两次这个接口,这是直接原因,让安卓减少调这个接口次数,问题可以解决。但就算安卓连续调两次,也不应该出现这种问题,这说明后端代码还是出现了问题,接下来就算继续debug调试排查。
经过多次调试,发现第一次进来没问题,数据完整产生,而且正常回调回去,紧接着第二次进来,走同样的代码,数据库已经有数据,但如下图缺一直读不到数据,一直是空的状态,开始怀疑mybatis缓存问题。
4、穿插一个知识,mybatis的一二级缓存
https://tech.meituan.com/2018/01/19/mybatis-cache.html
二级缓存介绍
在上文中提到的一级缓存中,其最大的共享范围就是一个SqlSession内部,如果多个SqlSession之间需要共享缓存,则需要使用到二级缓存。开启二级缓存后,会使用CachingExecutor装饰Executor,进入一级缓存的查询流程前,先在CachingExecutor进行二级缓存的查询,具体的工作流程如下所示。
二级缓存开启后,同一个namespace下的所有操作语句,都影响着同一个Cache,即二级缓存被多个SqlSession共享,是一个全局的变量。
当开启缓存后,数据的查询执行的流程就是 二级缓存 -> 一级缓存 -> 数据库。
总结
MyBatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到namespace级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强。
MyBatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。
在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cache接口实现,有一定的开发成本,直接使用Redis、Memcached等分布式缓存可能成本更低,安全性也更高。
与执行select不同的是,执行update,insert,delect操作后会清空一级缓存中的数据,而不是通过算法生成缓存的键值存入一级缓存,之所以有这种差别是因为 select的flushCache(清空缓存)默认为false,而update,insert,delect的flushCache(清空缓存)默认为true。
5.百度到的结果,很明显是清空缓存flushCache = true,如下图
6.使用百度的做法,进行调试,结果还是不尽人意,如下图还是重复数据。
7、这使我们开始怀疑,mybatis这个调试是否有用,是否真的清除缓存,带着这个疑问,开始调试数据库,看是否两次都有执行数据库查询,还是只有执行一次,代码如下图:
调试的结果是,已经执行了两次,缓存也清除,说明我们刚的做法没错,回头想一想,结合一二级缓存原理,增删改情况也会清除缓存,多次测试结果一样,问题还是没解决。
总结,不是mybatis的问题,后面开始对配置文件下手,感觉有问题,如下图配置,进行了修改补充,多次调试执行的结果还是一样,没有用。
百度到下图信息,看着好像很有道理,但感觉跟这个就没关系,所以就没去试,后面也证实这样做是对的:
8.接下操作开始比较贴近解决问题的方法了
事物问题,大哥提出了两个数据库产生事物锁的方法,要解决读取不到数据,或脏读的情况,如下图,每次进入该方法都会到数据库修改count字段,每次都加一,意思是要么都成功,要么都失败,这样就相当于数据库产生的事物锁。多次调试,每次进入同样会加一,说明这个锁的方向还是错误。
9.冲突问题
10.了解下事物的隔离级别
11.详细隔离级别和锁:https://www.cnblogs.com/tian666/p/7852646.html
12.最终解决问题的办法是,调整springboot的事物隔离级别,改成不可重复读级别就可以完美解决问题。
13.spring的7种事物传播行为
各个传播行为是干什么详解
https://www.cnblogs.com/ll409546297/p/11076258.html
评论 (0)