场景描述
对于一个多用户系统,多个用户可以同时处理同一个单据数据的情况,此时,如何防止同一时刻多个用户同时处理同一单据,造成数据脏读的情况?
解决思路
可以赋值当前单据一个状态唯一值,当用户进行单据数据处理提交时,检测是否满足状态唯一值的一致,如果一致,则允许进行修改,如果不一致,则不允许修改并且返回当前单据的最新数据。
解决方法
-
取当前单据的唯一标识记录(例如主键、或者由多个字段信息共同组成)作为存、取状态唯一值的标识;
-
对于这个数据的存储修改,最好是一个JsonObject对象,然后存储到redis数据库中,以便进行统一的归类、获取与修改;
-
第一,定义好一个对象(是全局每个用户通用的),该对象有什么数据,这些数据有什么处理方法(例如获取对象中的变量、更新变量的值等等);-->未必要,但是有的话比较方便和规范。
第二,将单据的唯一标识记录作为键,将状态唯一值作为值,然后每一次的‘点击修改’时,进行状态唯一值的更新(默认+1);
第三,需要考虑何时进行删除,一般来说可以从两方面入手,一是每天定时进行数据清理(或进行失效时间的配置),二是在存入时随即进行失效时间的配置(但是这个一般来说不是在一个对象里面了,一般是直接存入redis数据库)
-
实现时需要注意,单据的状态唯一值是从数据查询一同返回给前端的,前端进行修改提交时一并返回给后端。
问题
-
状态唯一值如何进行更新?即如何确保多个用户之间,对于同一单据是不重复的,否则会出现用户修改了当前的单据并提交时,存在状态唯一值一致的情况。
因为状态唯一值的使用价值在于修改保存时,保证数据的唯一性,确保不会出现数据脏读情况,所以状态唯一值的更新可以从保存、修改时入手。
即当进行单据的保存或修改成功后进行状态唯一值的更新(+1),此时只有重新刷新单据页面才可以重新获取到单据状态唯一值,从而进行修改数据。
-
如果用户量大,此时还可能出现数据修改提交时的高并发情况。即在修改时,本来是先校验当前单据状态唯一值是否一致的,然后在修改保存成功后才进行状态唯一值的更新,但是如果此时多个用户同一时刻对同一张单据都进行修改可能会出现状态唯一值还未进行更新,却存在多个修改任务进入到了修改保存程序,从而依然还是造成了数据脏读,那这种情况又应该如何处理?
第一种方案:在进行状态唯一值校验成功之后,随即进行状态唯一值的更新(无论之后的修改保存程序是否成功,如果不成功,随即将最新的状态唯一值也一并同错误信息一同返回给前端,确保当前的用户下载提交时当前的状态唯一值是尽可能最新的)。这样处理会将这种高并发出现脏读的几率降低。
但是依然存在问题。即假设一个用户进入到修改保存程序(假设未=为A)后,此时还未走完程序,然后另外一个用户第一次进入A时,状态唯一值不一致,然后重新获取。重新获取后再次进入到A,此时一致,开始走程序,但是上一个用户还没走完,那么此时就会再出现数据脏读的情况。
第二种方案:进行加锁处理。