AppBoxFuture(七): 分布式外键约束
关系数据库与NoSql其中的一个主要区别是具备完整的外键约束,虽说现在一些大厂在设计数据存储结构时禁止使用外键约束,靠业务逻辑来保证数据完整性,但考虑到是人就会犯错,为了保证关键业务数据的完整性,所以作者还是决定在存储引擎层面实现外键约束功能。
一、实现思路
由于存储引擎是分布式的,所以引用者与被引用者可能存在不同的节点上(如订单数据在节点1上,订单引用的产品数据在节点2上),这样实现外键约束的方式就会与传统关系数据库有些不一样,作者设计了如下图所示的存储结构,在RocksDB划分一个ColumnFamily存储引用索引(记录谁的某个成员引用了哪个目标),以及存储被引用者的计数器(记录哪个分区引用了我,被引用了多少次),通过分布式事务保证数据与引用索引及计数器的一致性。

根据上述设计,以下描述的逻辑可以得到保证(为了方便以下订单指引用者,产品指被引用者):
1.Insert订单
Insert时存储引擎根据实体模型元数据是否存在EntityRef成员,是则在同一事务内会向被引用者的分区自动发送AddRefCommand,该命令会锁定并判断是否存在相应的记录,如不存在则通知事务回滚。如果是同一事务内Insert产品再Insert订单,AddRefCommand会检测同一事务内是否存在被引用者记录。事务递交时原子保存引用索引与引用计数。
2.Delete产品
Delete时存储引擎先判断当前记录所有分区的引用计数值是否等于0,不等于0则通知事务回滚。
3.Update or Delete订单
如果引用的产品变更,则删除旧引用索引然后添加新引用索引;如果引用的产品设为Null或删除订单,则删除引用索引,同时通知产品分区更新引用计数。
二、并发优化
由于存储引擎的分布式事务是基于2PL实现的,如果大量不同的事务Insert订单且引用同一产品,会造成这些事务排队执行,从而导致并发性能不理想。作者做了个简单优化,允许不同事务的AddRefCommand共享锁定被引用者以提高并发性能。就上述场景作者简单测试了并发Insert带EntityRef的性能,单节点Debug模式约14000tps(I74C8G虚拟机),不带外键引用的并发Insert约28000tps。
三、简单测试
暂利用初始化时的实体Emploee及OrgUnit来做测试,OrgUnit.CreateById引用Emploee.Id。通过IDE新建一个服务模型,然后依次实现以下服务方法保存发布后将输入光标定位在需要测试的方法名称内,点击主菜单->Service->Invoke进行服务方法调用测试。
1.测试引用至不存在的目标
public async Task<string> Test1()
{
var ou = new Entities.OrgUnit();
ou.Name = "Name";
ou.CreateById = Guid.Empty; //指向不存在的目标
await EntityStore.SaveAsync(ou);
return "Done.";
}
调用此方法显示"Insert error: ForeignKeyConstraint", 即违反外键约束。
2.测试同一事务插入
public async Task<string> Test2()
{
var txn = await Transaction.BeginAsync();
try
{
//先新建并保存被引用者
var emp = new Entities.Emploee();
emp.Name = "Batch name";
emp.Account = emp.Name;
emp.Birthday = new DateTime(1977, 3, 16);
await EntityStore.SaveAsync(emp, txn);
//再新建并保存引用者
var ou = new Entities.OrgUnit();
ou.Name = "Batch ou";
ou.CreateById = emp.Id;
await EntityStore.SaveAsync(ou, txn);
await txn.CommitAsync();
}
catch (Exception ex)
{
txn.Rollback();
return $"Failed: {ex.Message}";
}
return "Done.";
}
调用此方法返回"Done.",此时可打开Emploee及OrgUnit的模型设计器内的"Data"栏验证插入的数据。
3.测试同一事务删除
public async Task<string> Delete()
{
var q1 = new TableScan<Entities.OrgUnit>();
q1.Filter(t => t.Name == "Batch ou");
var ous = await q1.ToListAsync();
var q2 = new TableScan<Entities.Emploee>();
q2.Filter(t => t.Name == "Batch name");
var emps = await q2.ToListAsync();
var txn = await Transaction.BeginAsync();
try
{
//先删除引用者, 如果注释这一行则存在外键约束导致下一行执行失败
await EntityStore.DeleteAsync(ous[0], txn);
//再删除被引用者
await EntityStore.DeleteAsync(emps[0], txn);
await txn.CommitAsync();
}
catch(Exception ex)
{
txn.Rollback();
return $"Failed: {ex.Message}";
}
return "Done.";
}
调用此方法返回"Done.",此时可打开Emploee及OrgUnit的模型设计器内的"Data"栏验证数据已被删除。
四、本篇小结
本篇主要介绍了框架集成的存储引擎如何用另类的方式实现外键约束,Github上的运行时已经更新可测试。如果您有问题或Bug报告,请留言或在Github提交Issue。
AppBoxFuture(七): 分布式外键约束的更多相关文章
- MySQL数据库--外键约束及外键使用
什么是主键.外键关系型数据库中的一条记录中有若干个属性,若其中某一个属性组(注意是组)能唯一标识一条记录,该属性组就可以成为一个主键. 比如: 学生表(学号,姓名,性别,班级) 其中每个学生的学号是唯 ...
- MySQL8.0数据库出现的问题——外码创建方式、外键约束两个引用列不兼容问题、check约束问题、用触发器代替check约束、关键字DELIMITER、删除添加索引、删除添加外键约束、和一些数据库方面的操作
一.首先先说一下我们都需要建立那些表 mysql> CREATE TABLE IF NOT EXISTS `student`( -> `sno` CHAR(8) NOT NULL, -&g ...
- mysql 外键约束备注
梳理mysql外键约束的知识点. 1.mysql外键约束只对InnoDb引擎有效: 2.创建外键约束如下: DROP TABLE IF EXISTS t_demo_product; CREATE TA ...
- 如果你发现mysql的外键约束不管用了
不知为何我机子上的mysql竟然默认关闭外键约束,导致我试了好多遍都可以插入非法值,以下语句可以开启约束 SET foreign_key_checks = 1; (0则关闭) 备忘
- Constraint6:更新外键约束(Foreign Key Constraint)的引用列
在SQL Server中,表之间存在引用关系,引用关系通过创建外键约束(Foreign Key Constraint)实现.如果一个Table中的column被其他Table引用,那么该表是参考表,或 ...
- MySql 外键约束 之CASCADE、SET NULL、RESTRICT、NO ACTION分析和作用
MySQL有两种常用的引擎类型:MyISAM和InnoDB.目前只有InnoDB引擎类型支持外键约束.InnoDB中外键约束定义的语法如下: ALTER TABLE tbl_name ADD [CON ...
- SQL Server 临时禁用和启用所有外键约束(高版本向低版本迁移数据)
--获得禁用所有外键约束的语句 select 'ALTER TABLE [' + b.name + '] NOCHECK CONSTRAINT ' + a.name +';' as 禁用约束 from ...
- SqlServer禁用启用触发器、外键约束
--禁用指定名称触发器 ALTER TABLE tbname DISABLE TRIGGER trigname --恢复指定名称触发器 ALTER TABLE tbname ENABLE TRIGGE ...
- sql查询指定表外键约束
//////////////////查询指定表外键约束select a.name as 约束名, object_name(b.parent_object_id) as 外键表, d.name as 外 ...
随机推荐
- 利用背景流量数据(contexual flow data) 识别TLS加密恶意流量
识别出加密流量中潜藏的安全威胁具有很大挑战,现已存在一些检测方法利用数据流的元数据来进行检测,包括包长度和到达间隔时间等.来自思科的研究人员扩展现有的检测方法提出一种新的思路(称之为“dataomni ...
- 怎样高速地安装Ubuntu SDK
我在先前的文章"Ubuntu SDK 安装"中已经具体地介绍了怎样安装Ubuntu SDK.可是非常多的开发人员可能在最后安装SDK所须要的chroots时候会失败.这里面的原因是SDK在安装chro ...
- 使用UltraISO刻录自己的音乐CD步骤
1.文件->新建->音乐光盘映像. 2.在左下方,“本地目录”中,找到音乐所在目录,右下方会出现mp3等音乐文件. 3.在右下方,点击音乐文件,右键选“添加”.音乐文件会出现在右上方窗口里 ...
- 【试水CAS-4.0.3】第06节_CAS服务端配置HTTPS
完整版见https://jadyer.github.io/2012/05/30/tomcat-https/ /** * @see CAS服务端配置HTTPS * @see -------------- ...
- Java学习之基本概念
1.java体系结构: j2se:是Java的标准版,用于标准的应用开. j2ee:是Java的企业版,用于企业级的应用服务,web服务开发. j2me:是Java的微型版,用户手机或嵌入式开发. p ...
- windows下安装elasticsearch6.2.4
window 下安装 elasticsearch 一.环境搭建需要的环境 1.jdk环境 2.Elasticsearch 3.git 环境 4.node 安装包 二.进行环境的搭建 1.解压Ela ...
- ACM-ICPC如何起步[转]
ACM-ICPC如何起步 刚刚绝定投身ACM-ICPC的同学先要过两关. 第一关:程序设计语言 如果学校有开设相关课程,则省去了很多麻烦.如果没有则可以选择<程序设计导引及在线实践>作为教 ...
- MySQL搭建系列之多实例
所谓多实例.就是在一台server上搭建.执行多个MySQL实例,每一个实例使用不同的服务port.通过不同的socket监听:物理上,每一个实例拥有独立的參数配置文件及数据库. 通常情况下.一台se ...
- Jupyter notebook 使用Turorial
The cell magics in IPython http://nbviewer.jupyter.org/github/ipython/ipython/blob/1.x/examples/note ...
- MD5介绍及Windows下对文件做md5校验。
MD5介绍参考百度百科: 摘要如下: MD5 校验和(checksum)通过对接收的传输数据执行散列运算来检查数据的正确性. 一个散列函数,比如 MD5,是一个将任意长度的数据字符串转化成短的固定长度 ...