將通用的序列號生成器庫 從SQL Server遷移到Mysql 遇到的一個問題,就是TimeStamp/RowVersion並發控制類型在非Microsoft SQL Server數據庫中的實現。SQL Server timestamp 數據類型與時間和日期無關。SQL Server timestamp 是二進制數字,它表明數據庫中數據修改發生的相對順序。實現 timestamp 數據類型最初是為了支持 SQL Server 恢復算法。每次修改頁時,都會使用當前的 @@DBTS 值對其做一次標記,然後 @@DBTS 加1。這樣做足以幫助恢復過程確定頁修改的相對次序,但是 timestamp 值與時間沒有任何關系。 而在MySQL中,TIMESTAMP列類型提供一種類型,你可以使用它自動地用當前的日期和時間標記INSERT或UPDATE的操作。如果你有多個TIMESTAMP列,只有第一個自動更新。
在Entity Framework 中采用IsConcurrencyToken配置後RowVersion即自動用於where子句中用於比較Row Version, 我們也需要使用這個特性實現並發控制,Ak.Ini的博文http://www.cnblogs.com/akini/archive/2013/01/30/2882767.html ,我們按照這篇文章的方法在Entity framework core上面解決並發控制問題。
定義的序列號類型:
[Table("DbServerSequence")]
public class DbServerSequence : ISequence
{
public DbServerSequence()
{
}
public DbServerSequence(SequenceOptions options):this()
{
StartAt = options.StartAt;
CurrentValue = StartAt;
Increment = options.Increment;
MaxValue = options.MaxValue;
MinValue = options.MinValue;
Cycle = options.Cycle;
}
public String Key { get; set; }
public long StartAt { get; set; }
public int Increment { get; set; }
public long MaxValue { get; set; }
public long MinValue { get; set; }
public bool Cycle { get; set; }
public long CurrentValue { get; set; }
[ConcurrencyCheck]
public DateTime RowVersion { get; set; }
public DateTime DateCreated { get; set; }
}
其中RowVersion 是用作並發控制的,針對Mysql 不允許byte[]類型上標記TimeStamp/RowVersion,這裡使用DateTime類型。
數據庫表定義如下(自MySQL 5.6.5版本開始,DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP 選項也可以應用到Datetime類型的列):
DROP TABLE IF EXISTS `dbserversequence`;
CREATE TABLE `dbserversequence` (
`Key` varchar(128) NOT NULL,
`StartAt` bigint(20) NOT NULL,
`Increment` int(11) NOT NULL,
`MaxValue` bigint(20) NOT NULL,
`MinValue` bigint(20) NOT NULL,
`Cycle` bit(1) NOT NULL,
`CurrentValue` bigint(20) NOT NULL,
`RowVersion` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`DateCreated` datetime NOT NULL,
PRIMARY KEY (`Key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
在 SequenceDbContext 的OnModelCreating 重寫如下,主要是配置並發控制字段:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<DbServerSequence>(e =>
{
e.HasKey(x => x.Key);
e.Property(x => x.RowVersion).IsRowVersion().IsConcurrencyToken();
});
}
這個方案同時適用各種數據庫,尤其是類似MySql和Postgresql這種不支持默認RowVersion字段的數據庫。 最新的代碼放在https://github.com/geffzhang/Sequence/tree/dotnetcore