流水號(hào)作為唯一編號(hào),在銀行以及財(cái)務(wù)業(yè)務(wù)系統(tǒng)中尤為常見。
在設(shè)計(jì)中一般采用年、月、日等遞增方式,列如:2018012200001,表示2018年1月22日的第一個(gè)編號(hào)。
傳統(tǒng)的處理方式
常見數(shù)據(jù)庫遞增不能按年、月、日格式生成遞增編號(hào),不過可以通過其他方式實(shí)現(xiàn),如在 MSSQL 數(shù)據(jù)庫中可以采用觸發(fā)、自定義函數(shù)實(shí)現(xiàn)。
新建一個(gè)表 Order,必須擁有以下三個(gè)字段
| 名稱 | 類型 | 說明 |
|---|---|---|
| Code | nvarchar(32) | 用于存儲(chǔ)完整的流水號(hào) |
| Seed | bigint | 種子值,考慮大數(shù)據(jù)量的情況采用 bigint 類型 |
| Date | datetime | 當(dāng)前時(shí)間 |
觸發(fā)器代碼創(chuàng)建
IF (OBJECT_ID('TGR_Order_INSERT', 'TR') IS NOT NULL) DROP TRIGGER TGR_Order_INSERT
GO
CREATE TRIGGER TGR_Order_INSERT ON Order FOR INSERT
AS
BEGIN
BEGIN tran
DECLARE @OrderID UNIQUEIDENTIFIER, @Seed BIGINT
SET @Seed = ISNULL((SELECT MAX(Seed) FROM Order WITH (TABLOCK, HOLDLOCK) WHERE DATEDIFF(DAY, Date, GETDATE()) = 0 AND Seed > 0), CAST(CONVERT(NVARCHAR(8), GETDATE(), 112) + N'0000000000' AS BIGINT)) -- 取得當(dāng)前最大一個(gè)流水號(hào)種子,如果不存在使用默認(rèn)值
DECLARE OrderCursor CURSOR FOR SELECT OrderID FROM INSERTED
OPEN OrderCursor
FETCH NEXT FROM OrderCursor INTO @OrderID
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Seed = @Seed + 1 --遞增種子號(hào)
UPDATE Order SET Seed = @Seed, Code = CAST(@Seed AS NVARCHAR(18)) WHERE OrderID = @OrderID
FETCH NEXT FROM OrderCursor INTO @OrderID
END
CLOSE OrderCursor
DEALLOCATE OrderCursor
COMMIT tran
END
GO
- 注意該觸發(fā)使用了游標(biāo),為了保證數(shù)據(jù)計(jì)算的準(zhǔn)確性進(jìn)行鎖表操作。
- 稍作修改即可改為自定義函數(shù),這里我就不再寫出自定義函數(shù)的創(chuàng)建。
- 可以見得這種方式在海量與高并發(fā)的數(shù)據(jù)環(huán)境中,就顯得先天不足。
memcached
memcached 本身就是為高并發(fā)和快速存取誕生的,并且他還自帶了增量方法。
以下示例開發(fā)語言是 C# 所以采用 EnyimMemcached 作為客戶端,數(shù)據(jù)框架 Entity Framework。
在程序啟動(dòng)時(shí)初始化種子
var date = DateTime.Now;
using (var context = new DbContext())
{
var seed = context.Order.Where(m => DbFunctions.DiffDays(m.Date, date) == 0).Max(m => (long?)m.Seed) ?? 0;
new MemcachedClient().Store(StoreMode.Set, "Test_" + date.ToString("yyyyMMdd"), seed.ToString(), TimeSpan.FromHours(25));
}
- ASP.NET 可以在 Application_Start 中初始化。
- 因?yàn)榘刺爝f增,所以保存過期時(shí)間大于24小時(shí)即可。
插入數(shù)據(jù)的實(shí)體賦值
var date = DateTime.Now;
var seed = new MemcachedClient().Increment("Test_" + date.ToString("yyyyMMdd"), 1, 1, TimeSpan.FromHours(25));
var entity = new Order {
Code = date.ToString("yyyyMMdd") + seed .ToString().PadLeft(14, '0'),
Seed = seed,
Date = date
};
/* 這里將實(shí)體保存到數(shù)據(jù)庫即可 */
文章就寫到這里,這只是 memcached 的一種應(yīng)用,在網(wǎng)站訪問統(tǒng)計(jì)、防刷新機(jī)制等方面你都可以使用它。