关系型数据库表结构的两个设计技巧

关系型数据库表结构的设计,有下面两个设计技巧:sql

物理主键做为关联的外键

关系型数据库,由多个数据表构成。每个数据表的结构是相同的,不一样表之间可能存在关联关系。表之间的关联关系,正是关系型数据库得名的缘由。数据库

一个表由多个字段构成。其中可能有多个字段适合做为主键。主键字段,就是表中每一行都不会有重复数据的字段。
主键,能够分为两种:物理主键和逻辑主键。
每一张数据库的表,都使用自增加的id字段做为物理主键。
多表之间的外键关联,都关联其余表的物理主键,也就是关联其余表的id字段。并发

逻辑主键,就是除了id字段外的不重复的字段。咱们设计数据库的外键关联时,不使用逻辑主键,而是使用物理主键。性能

这是由于,物理主键确定是主键,由于它是自增的。(对于不支持自增字段的关系数据库,可使用uuid保证物理主键的惟一性)ui

而逻辑主键,则可能随着业务的发展,成为可重复的字段。一旦这种状况发生,关系数据库的外键关系就被破坏了。如,可能你以为姓名是逻辑主键,但可能后面发现有人重名,那么这个字段就再也不是主键了。而若是以前使用这个字段做为外键,那么查询返回的数据就不是一一对应的了。spa

这就是为何要使用物理主键,以及用物理主键做为关联外键的缘由。设计

使用乐观锁更新依赖以前状态的记录

考虑这样一种数据库的应用场景:code

任务单的接管:多个操做人员从一个任务池中接管一个任务。只有第一个获取任务的操做人员才能成功接管该任务,后续操做人员的接管操做都必须失败。事务

这时,就须要一种数据库记录的锁定机制。只有第一个事务才能更新记录。ci

数据库可使用悲观锁和乐观锁来锁定数据库记录。

悲观锁是以下sql语句实现的:

1
SELECT * FROM t FOR UPDATE

这条语句会在其余修改内容的事务提交后返回最新的数据。

一旦执行这条语句,这些记录就被锁住了,不能被其余sql事务修改。直到本事务提交。

乐观锁,是应用程序实现的,不是数据库实现的机制。乐观锁,对于数据库来讲,就是没有上锁。事务能够select其余事务已经提交的数据。更新数据时,数据库保证多个事务的更新是原子的。

悲观锁,会致使事务等待其余事务完成。乐观锁,只会等待其余事务的更新语句的完成,不会等待整个事务完成,所以效率较高。

实现乐观锁的方法:

给数据库表添加一个version字段。version是一个数字类型的字段,每次更新都加1。每次更新时都要检测version字段是否和当前事务的值相同。若是version字段不一样,那么就代表在查询数据以后,有其余事务已经更新了该记录,就会致使这次更新失败。应用必须从新载入最新的数据,而后从新更新数据。

若是使用乐观锁,那么若是数据库中version和应用中version相同,则用version+1的版本值更新version字段。
SQL语句以下:

1
update studentVersion set ver=?, name =? where id=? and ver=?

不使用锁更新独立状态的记录

考虑这样一种数据库的应用场景:

须要更新虚拟机的状态。多个事务可能会同时更新虚拟机的状态为start或者stop。这种状态的更新和前一个阶段的状态是无关的,所以不须要锁定记录。直接更新便可。此时不须要使用悲观锁或者乐观锁。

若是这个表添加了version字段,直接忽略对version字段的比较和更新便可。

SQL语句以下:

1
update studentVersion set   name =? where id=?

总结

设计关系型数据库的表时,须要给表添加一个ID字段(自增字段,或者uuid字段)和一个version字段(数值类型)。ID字段做为物理主键,用于保证记录的不可重复性和用做外键关联。

version字段用于实现乐观锁,提供比悲观锁更好的性能。特别是对于UI显示并可能出现并发更新的数据,更须要使用乐观锁来提高数据库访问性能。

对于后台自动更新的任务,可使用乐观锁实现。但须要在冲突发生时实现自动退让。也可使用悲观锁在数据库上对事务进行排队来解决更新冲突问题。

对于不关心记录的状态之间关系的场景,能够直接更新记录,忽略掉version字段的检测和更新。

相关文章
相关标签/搜索