zoukankan      html  css  js  c++  java
  • [C#]实现序列号生成器

    来自:http://www.cnblogs.com/leafyoung/archive/2005/10/10/251436.html

    对于数据库应用而言, 一个合适的序列号生成器是非常有用的, 用它我们可以方便地给新增的记录的id字段(主键)赋值, 当然我们同样可以用Identity类型主键, 但是假如同时存在父子关系的记录, 那么给子记录赋parent_id就极为不便, 我们必须先将父记录插入到数据库, 然后从数据库中取得自动生成的id, 然后才成给子记录的parent_id字段赋值. 毫无疑问, 假如我们可以给父记录的id直接赋值的话, 问题就简单得多了.
        但是, 对于一个分布式应用而言, 不经过周密的考虑往往会带来id重复的问题. 在我们公司既有的产品中采用段号来解决这个问题, 就是说为每个用户分配一个足够长的区间(比如10000000)作为可选id, 每个用户使用独立的区间的id一般不会带来问题, 但是作为一个完美主义者来说, 不能不考虑到一个极端情况, 假如区间重叠了怎么办? 而且这样的分配方式无疑极大地浪费了id资源, 是否有更好的解决方案呢?
        前几天阅读Martin Fowler的大作<Patterns of Enterprise Application Architecture>, 其中提到了一种不错的解决方案, 即使利用键表(key table), 典型的键表有两列: 名字(name)和下一个有效id(nextID). 如果使用数据库唯一键的话, 这个表只有一条记录, 如"DB, 1"; 如果使用表唯一键, 那么对于每个数据库表都有一行数据与之对应, 比如: "Users, 11", "Roles, 31"等等. 我们要获得一个新的可用id, 只需要从一个合适的行中获得nextID值, 然后把nextID + incrementBy存入数据库, 这里每次加上一个incrementBy是为了减少数据库的操作, 避免浪费宝贵的数据库连接资源, 减少冲突发生的可能行.
        下面看看我在.net下的实现(模仿Martin Fowler的大作):
    using System; 
    using System.Diagnostics; 
    using System.Data; 
    using System.Data.Common;

    namespace MyProject.Core
    {
        
    public class KeyGenerator
        {
            
    #region private members

            
    private IDbConnection _connection = null;
            
    private string _keyName;
            
    private int _incrementBy;
            
    private long _nextId = 0;
            
    private long _maxId = 0;

            
    #endregion

            
    public KeyGenerator(IDbConnection conn, string keyName, int incrementBy)
            {
                _connection 
    = conn;
                _keyName 
    = keyName;
                _incrementBy 
    = incrementBy;
            }

            
    public long NextKey
            {
                
    get
                {
                    
    if (_nextId == _maxId)
                    {
                        reserveIds();
                    }
                    
    return _nextId++;
                }
            }

            
    private void reserveIds()
            {
                IDbTransaction tx 
    = _connection.BeginTransaction();
                IDbCommand cmd 
    = _connection.CreateCommand();
                cmd.Transaction 
    = tx;
                
    try
                {
                    cmd.CommandText 
    = string.Format(
                        
    "update keys set nextID = nextID + {0} where name = \'{1}\'",
                        _incrementBy, _keyName);
                    
    int result = cmd.ExecuteNonQuery();
                    Debug.Assert(result 
    == 1, _keyName + " not exists");
                    cmd.CommandText 
    = string.Format("select nextID from keys where name = \'{0}\'",
                        _keyName);
                    _maxId 
    = Convert.ToInt64(cmd.ExecuteScalar());
                    _nextId 
    = _maxId - _incrementBy;
                    tx.Commit();
                }
                
    catch (Exception ex)
                {
                    tx.Rollback();
                    
    throw ex;
                }
                
    finally
                {
                    cmd.Dispose();
                }
            }
        }
    }

    使用的方法也很简单, 如下所示:

    OleDbConnection conn = new OleDbConnection(); 
    conn.ConnectionString 
    =  
        
    "Provider=SQLOLEDB;Data Source=(local);Initial Catalog=gcs;Trusted_Connection=Yes"
    conn.Open(); 
     
    KeyGenerator gen 
    = new KeyGenerator(conn, "Users"10); 
     
    for (int i = 0; i < 10; i++

        Console.WriteLine(gen.NextKey); 

     
    conn.Close(); 

    附: 创建键表的sql

    CREATE TABLE [keys] ( 
        [name] [varchar] (
    32) COLLATE Chinese_PRC_CI_AS NOT NULL , 
        [nextID] [
    int] NULL , 
         PRIMARY KEY  CLUSTERED  
        ( 
            [name] 
        )  ON [PRIMARY]  
    ) ON [PRIMARY] 
  • 相关阅读:
    剑指Offer-用两个栈实现队列
    剑指Offer-从尾到头打印链表
    滑动门技术实现
    解决keil5中文注释乱码方法
    faker数据填充详解
    redis在微博与微信等互联网应用笔记
    JDBC插入中文数据出现?号地解决问题
    idea配置less自动编译
    idea使用Vue的v-bind,v-on报错
    idea 代码部分格式化
  • 原文地址:https://www.cnblogs.com/liufei88866/p/1766623.html
Copyright © 2011-2022 走看看