浅谈c#在网络波动时防重复提交的方法

  

前几天,公司数据库出现了两条相同的数据,而且时间相同(毫秒也相同)。排查原因,发现是网络波动造成了重复提交。

  

由于网络波动而重复提交的例子也比较多:

  

浅谈c#在网络波动时防重复提交的方法

  

浅谈c#在网络波动时防重复提交的方法”>,</p>
  <p>网络上,防重复提交的方法也很多,使用复述,锁,代码层面使用锁。</p>
  <p>但是,我没有发现一个符合我心意的解决方案。因为网上的解决方案,第一次提交返回成功,第二次提交返回失败。由于两次返回信息不一致,一次成功一次失败,我们不确定客户端是以哪个返回信息为准,虽然我们希望客户端以第一次返回成功的信息为准,但客户端也可能以第二次失败信息运行,这是一个不确定的结果。</p>
  <p>在重复提交后,如果客户端的接收到的信息都相同,都是成功,那客户端就可以正常运行,就不会影响用户体验。</p>
  <p>我想到一个缓存类,来源于PetaPoco。</p>
  <p> <强> Cache<TKey TValue>代码如下:</强> </p>
  
  <pre类=   公共类Cache   {   私人只读的ReaderWriterLockSlim _lock=new ReaderWriterLockSlim ();   私人只读的Dictionary_map=new Dictionary ();      公共int数{   {回报_map.Count;}   }      公共TValue执行(TKey键,Func工厂)   {//检查缓存   _lock.EnterReadLock ();   TValue val;   尝试{   如果(_map。TryGetValue(关键,val))   返回val;   最后}{   _lock.ExitReadLock ();   }//缓存   _lock.EnterWriteLock ();   尝试{//检查再一次   如果(_map。TryGetValue(关键,val))   返回val;//创建它   val=工厂();//存储   _map。添加(关键,val);//完成   返回val;   最后}{   _lock.ExitWriteLock ();   }   }      公共空间Clear ()   {//缓存   _lock.EnterWriteLock ();   尝试{   _map.Clear ();   最后}{   _lock.ExitWriteLock ();   }   }   }      

Cache   

但是,细细分析Cache类,可以发现有以下几个缺点

  

1,不会自动清空缓存,适合一些关键不多的数据,不适合做为网络接口。

  

2,由于_lock.EnterWriteLock,多线程会变成并单线程,不适合做为网络接口。

  

3,没有过期缓存判断。

  

于是我对Cache进行改造。

  

AntiDupCache代码如下:

     ///& lt; summary>///防重复缓存///& lt;/summary>///& lt; typeparam name=" TKey祝辞& lt;/typeparam>///& lt; typeparam name=" TValue祝辞& lt;/typeparam>   公共类AntiDupCache   {   私人只读的int _maxCount;//缓存最高数量   私人只读的长_expireTicks;//超时蜱虫   私人长_lastTicks;//最后蜱虫   私人只读的ReaderWriterLockSlim _lock=new ReaderWriterLockSlim ();   私人只读的ReaderWriterLockSlim _slimLock=new ReaderWriterLockSlim ();   私人只读的Dictionary比;_map=new Dictionary在();   私人只读的Dictionary_lockDict=new Dictionary ();   私人只读的Queue_queue=new Queue ();   类AntiDupLockSlim: ReaderWriterLockSlim{公共int UseCount;}///& lt; summary>///防重复缓存///& lt;/summary>///& lt;参数name=" maxCount祝辞缓存最高数量,0不缓存,1缓存所有& lt;/param>///& lt;参数name=" expireSecond祝辞超时秒数,0不缓存,1永久缓存& lt;/param>   公共AntiDupCache (int maxCount=100, int expireSecond=1)   {   如果(maxCount & lt;0){   _maxCount=1;   其他}{   _maxCount=maxCount;   }   如果(expireSecond & lt;0){   _expireTicks=1;   其他}{   .Ticks _expireTicks=expireSecond * TimeSpan.FromSeconds (1);   }   }///& lt; summary>///个数///& lt;/summary>   公共int数{   {回报_map.Count;}   }///& lt; summary>///执行///& lt;/summary>///& lt;参数name=肮丶弊4侵? lt;/param>///& lt;参数name="工厂"祝辞执行方法& lt;/param>///& lt; returns> & lt;/returns>   公共TValue执行(TKey键,Func工厂)   {//过期时间为0则不缓存   如果对象。=(null,键)| | _expireTicks==0 l | | _maxCount==0){返回工厂();}      TValue> Tuple

浅谈c#在网络波动时防重复提交的方法