将通用的序列号生成器库 从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
{
e.HasKey(x => x.Key);
e.Property(x => x.RowVersion).IsRowVersion().IsConcurrencyToken();
});
}
这个方案同时适用各种数据库,尤其是类似MySql和Postgresql这种不支持默认RowVersion字段的数据库。 最新的代码放在https://github.com/geffzhang/Sequence/tree/dotnetcore