zoukankan      html  css  js  c++  java
  • .NET:防止并发修改 之 离线悲观锁代码示例(离线悲观锁)

    背景

    系统会出现并发,上篇文章我介绍了如何使用“离线乐观锁”保证并发,离线乐观锁适合处理那些重新编辑成本不大的单据,如果某个单据用户花了10分钟进行编辑,提交时你告诉他出现并发了,他心里肯定会骂娘的,今天介绍的“离线悲观锁”就可以避免这种情况。

    思路

    小明签出了源代码,小强就不能签出了,我们目前的源代码系统就是用的这种悲观策略。

    实现

    核心代码

    离线悲观锁管理器接口

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Happy.Application.PessimisticLock
     8 {
     9     /// <summary>
    10     /// 离线悲观锁管理器接口。
    11     /// </summary>
    12     public interface ILockManager
    13     {
    14         /// <summary>
    15         /// 获取锁。
    16         /// </summary>
    17         /// <param name="entity">锁的主体,如:表名或聚合名。</param>
    18         /// <param name="key">锁的主体的唯一标识,如:主键或唯一索引。</param>
    19         /// <param name="owner">锁的拥有者,如:UserId或SessionId。</param>
    20         /// <returns>获取锁成功就返回true,否则返回false。</returns>
    21         bool AcquireLock(string entity, string key, string owner);
    22 
    23         /// <summary>
    24         /// 释放锁。
    25         /// </summary>
    26         /// <param name="entity">锁的主体,如:表名或聚合名。</param>
    27         /// <param name="key">锁的主体的唯一标识,如:主键或唯一索引。</param>
    28         /// <param name="owner">锁的拥有者,如:UserId或SessionId。</param>
    29         void ReleaseLock(string entity, string key, string owner);
    30 
    31 
    32         /// <summary>
    33         /// 释拥有者的所有锁。
    34         /// </summary>
    35         /// <param name="owner">锁的拥有者,如:UserId或SessionId。</param>
    36         void ReleaseLocks(string owner);
    37     }
    38 }

    基于内存的离线悲观锁管理器

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 
      7 using Happy.DesignByContract;
      8 using Happy.Application.PessimisticLock.Internal;
      9 
     10 namespace Happy.Application.PessimisticLock
     11 {
     12     /// <summary>
     13     /// 基于内存的离线悲观锁管理器。
     14     /// </summary>
     15     public sealed class MemoryLockManager : ILockManager
     16     {
     17         private static readonly Dictionary<string, MemoryLockItem> _items = new Dictionary<string, MemoryLockItem>();
     18 
     19         /// <inheritdoc />
     20         public bool AcquireLock(string entity, string key, string owner)
     21         {
     22             entity.MustNotNullAndNotWhiteSpace("entity");
     23             key.MustNotNullAndNotWhiteSpace("key");
     24             owner.MustNotNullAndNotWhiteSpace("owner");
     25 
     26             var item = MemoryLockItem.Crete(entity, key, owner);
     27 
     28             lock (_items)
     29             {
     30                 if (!IsLocked(item.Identifier))
     31                 {
     32                     SetLockItem(item);
     33 
     34                     return true;
     35                 }
     36 
     37                 return IsLockedBy(item);
     38             }
     39         }
     40 
     41         /// <inheritdoc />
     42         public void ReleaseLock(string entity, string key, string owner)
     43         {
     44             entity.MustNotNullAndNotWhiteSpace("entity");
     45             key.MustNotNullAndNotWhiteSpace("key");
     46             owner.MustNotNullAndNotWhiteSpace("owner");
     47 
     48             var item = MemoryLockItem.Crete(entity, key, owner);
     49 
     50             lock (_items)
     51             {
     52                 if (!IsLockedBy(item))
     53                 {
     54                     throw new InvalidOperationException(string.Format(Messages.Error_CanNotReleaseLock, owner));
     55                 }
     56 
     57                 RemoveLockItem(item);
     58             }
     59         }
     60 
     61         /// <inheritdoc />
     62         public void ReleaseLocks(string owner)
     63         {
     64             lock (_items)
     65             {
     66                 foreach (var keypair in _items)
     67                 {
     68                     if (keypair.Value.Owner == owner)
     69                     {
     70                         RemoveLockItem(keypair.Value);
     71                     }
     72                 }
     73             }
     74         }
     75 
     76         private static bool IsLocked(string identifier)
     77         {
     78             return _items.ContainsKey(identifier);
     79         }
     80 
     81         private static void SetLockItem(MemoryLockItem item)
     82         {
     83             _items[item.Identifier] = item;
     84         }
     85 
     86         private static bool IsLockedBy(MemoryLockItem item)
     87         {
     88             if (!IsLocked(item.Identifier))
     89             {
     90                 return false;
     91             }
     92 
     93             return _items[item.Identifier].Owner == item.Owner;
     94         }
     95 
     96         private static void RemoveLockItem(MemoryLockItem item)
     97         {
     98             _items.Remove(item.Identifier);
     99         }
    100     }
    101 }

    离线悲观锁代理

     1 /**
     2  * 离线悲观锁代理。
     3  * 
     4  * @static
     5  * @class PessimisticLockProxy
     6  * @namespace Happy.server
     7  */
     8 Ext.define('Happy.server.PessimisticLockProxy', {
     9     alternateClassName: ['PessimisticLockProxy'],
    10     singleton: true,
    11     requires: ['Happy.Ajax'],
    12 
    13     acquireLock: function (entity, key, success, failure) {
    14         var me = this;
    15 
    16         Happy.Ajax.callAction({
    17             url: '/LockManager/AcquireLock',
    18             params: { entity: entity, key: key },
    19             success: success,
    20             failure: failure
    21         });
    22     },
    23 
    24     releaseLock: function (entity, key, success, failure) {
    25         var me = this;
    26 
    27         Happy.Ajax.callAction({
    28             url: '/LockManager/ReleaseLock',
    29             params: { entity: entity, key: key },
    30             success: success,
    31             failure: failure
    32         });
    33     }
    34 });

    运行效果

     

    代码下载

    地址:http://happy.codeplex.com/SourceControl/latest。因为项目正在重构中,请下载最新源代码,不要下载Happy-1.0.0.3

    如何使用代码

    备注

    尽量通过合理的设计规避离线悲观锁,应用场景不会有很多,有使用过的朋友,请留下您宝贵的意见。

  • 相关阅读:
    阿里巴巴人力资源挖坑 面试技术挑战题
    •••| 卡牌游戏诞生记 |•••
    JavaScript:js-cookie存取
    乘积最大
    最大的算式
    KMP笔记√//找最大子串,前缀自匹配长度
    牛棚回声
    P1027 木瓜地
    P1026 犁田机器人
    P1023 奶牛的锻炼
  • 原文地址:https://www.cnblogs.com/happyframework/p/3107389.html
Copyright © 2011-2022 走看看