关于生成并发唯一性流水号的解决方案
看了文章《弃用数据库自增ID,曝光一下我自己用到的解决方法 》,居然还显示到首页上去。我却觉得如果新手不辨真假,盲目顺从,那么会造成误人子弟的事实。
首先从作者的写这篇文章的目的上讲他想实现的无非是下面
目的:
1、不用自增长ID,因为自增长移植的时候不方便。
2、这个存储过程可以很高效的产生唯一性的自增长ID
从我小虎的认知上来回答:
1、对于作者的第一点,完全可以用Guid来替代自增长,或者在移植的时候,可以先去掉自增长的属性。有的人说Guid性能比不上自增长ID,这里我们先不讨论这一点,个
人认为效率问题主要体现在索引技巧上。
2、关键是作者的第二点,完全是不正确的,也是我写这篇文章的首要目的。因为这个存储过程根本就没有实现在多并发(多用户)的情况下能真正产生唯一性的主键ID。
我们看原作者的代码:

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

请看我的测试代码以及并发结果图





















结果图1

从上面多线程的测试效果上来说,绝对不要去按照原
作者的方法去做。
不厚道,说我只说不做,所以,我打算就再写一个切实可行的例子,供大家参考,仅仅作为抛砖引玉。
但是本人是经过多线程测试的,至少在我测试情况下
不会出现并发出差错的情况。
1、表结构和效果图,这个表是用来存储基础因子的,需要的可以拓展字段,比
如,升序,降序,起始序号等。









(PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,





2

3

4

5

6

7

8

GetSerialNo
9

10

11

12

13

14

15

16

17

18

19

20

21

22

锁定该条记录,好多人用lock去锁,起始这里只要执行一句update就可以了
23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

![]() |
![]() |
![]() |
第一张图(左)是单独对进货单执行循环多进程
第二张图(中)是单独对发货单执行循环多进程
第三张图(右)是对进货单发货单同时执行循环多进程
也就是上面三个Thread,自己注释测试就可以了。
测试并发代码
1protected void Page_Load(object sender, EventArgs e)
2 {
3 if (!IsPostBack)
4 {
5 for (int i = 0; i < 100; i++)
6 {
7 System.Threading.Thread temp = new System.Threading.Thread(new System.Threading.ThreadStart(Run));
8 System.Threading.Thread temp2 = new System.Threading.Thread(new System.Threading.ThreadStart(Run2));
9 System.Threading.Thread temp3 = new System.Threading.Thread(new System.Threading.ThreadStart(Run3));
10 temp.Start();
11 temp2.Start();
12 temp3.Start();
13 }
14 }
15 }
16
17 private void Run()
18 {
19 System.Data.SqlClient.SqlParameter[] p = {
20 new System.Data.SqlClient.SqlParameter("@sCode", "JHD") };
21 Response.Write(SqlHelper.ExecuteStoredProcedure("GetSerialNo", p).Rows[0][0].ToString() + "<br/>");
22 }
23 private void Run2()
24 {
25 System.Data.SqlClient.SqlParameter[] p = {
26 new System.Data.SqlClient.SqlParameter("@sCode", "XSD") };
27 Response.Write(SqlHelper.ExecuteStoredProcedure("GetSerialNo", p).Rows[0][0].ToString() + "<br/>");
28 }
29 private void Run3()
30 {
31 System.Data.SqlClient.SqlParameter[] p = {
32 new System.Data.SqlClient.SqlParameter("@table_name", "test"),
33 new System.Data.SqlClient.SqlParameter("@key_value",System.Data.SqlDbType.Int) };
34 p[1].Direction = System.Data.ParameterDirection.Output;
35 SqlHelper.ExecuteStoredProcedure("up_get_table_key", p);
36 Response.Write(p[1].Value.ToString() + "<br/>");
37 }
38
总结:我写的整个方法和存储
过程如果要实现流水号的话,还是相当可以的。在当前测试过程中是可以避免并发而导致数据的同步性出错的情况。