关系型数据库系列--(1)开篇杂记

来源:互联网 发布:局域网视频会议软件 编辑:程序博客网 时间:2024/05/20 02:29

工作3年了,接触的数据库不算多,第一份工作从事Web相关开发,用过MySQL,后来投身传统软件行业,就随波逐流用起来Oracle。但目前各家公司基本都有自己的框架或开发平台,对数据库的访问基本都隔离到DAO层中了,操作数据库基本都是面向对象操作(O/R Map),需要自己写SQL的地方都不多了,更别说其他一些更细节的操作。但对数据库相关的一些东西理解一下还是必要的。

首先说一下数据库的事务,事务具有ACID这四种特性。A(Atomic):原子性,数据库系统会保证单条SQL语句执行要么成功要么失败,但多条SQL语句数据库系统就不会主动做这种保证,同一个事务内多条SQL语句从逻辑上被视为一条语句,要么同时成功要么同时失败。C(Consistent):一致性,一个事务执行后会明确将数据库由状态1变为状态2或维持状态1不变,不会有其他状态出现。I(Isolation):隔离性,两个事务之间的执行对对方的可视程度,这个数据库系统均存在事务隔离级别,通过数据库锁实现的。D(Durable):持久性,一个事务执行成功后产生的效应是真实反映在数据库系统上的。

对于事务的隔离级别,数据库设计者总结了多个事务执行中互相影响可能会出现如下问题:

1》  Dirty Read(脏读):事务A读到了另一个未提交事务B修改后的数据,这个数据在事务B后续执行中可能还会被修改,是一个临时数据,脏数据。

2》 UnRepeatable Read(不可重复读):事务A不会读到未提交的数据,但会出现这种情况,事务A开始时读了一行数据,并开始不涉及到该行数据的其他操作,事务B此时对这行数据进行了修改并提交,事务A在这个时间点后再次去读这行数据,发现和第一次读到的值已经不同。

3》 Phantom(幻读):事务A读到的数据不会被其他事务贸然修改,但又会出现这种情况,事务A开始执行一条查询语句得到10条有效数据,然后去执行其他操作。事务B此时向该表又插入一条符合事务A查询条件的数据并提交,事务A在这个时间点后再去执行同样的查询语句会得到11条数据。

通常数据库系统会通过自身的锁机制,提供如下4种数据库事务隔离级别,以应对上述问题,用户可以根据实际需要将自己的DBMS设置到某个级别即可:

1》Read UnCommitted :事务A可以读到未提交的数据,即读操作不会加锁也不会检测所读数据上是否存在锁。这里需要明确一点,数据库系统默认写操作一定会往数据上加行级排他锁,所以一条数据肯定不会被两个事务同时修改。在这个隔离级别,效率最高,但上述3种问题统统会出现!目前没有数据库系统默认设置到这种隔离级别。

2》Read Committed :事务A只能读到提交后的数据,即读操作会往其读到的行数据上加行级共享锁,如果该行数据上存在排它锁,则事务A会挂起,处于等待状态!当读操作获得所有行数据后,事务A会立即撤销所有的行级共享锁而不是等待事务执行完毕才去释放行级锁。在这种隔离级别,会避免第1种问题,第2,第3种问题会出现。目前Sql Server, Oracle 默认都使用这种事务隔离级别。

3》Repeatable Read :事务A在读取到其行数据后,向所有数据加行级共享锁,并且直到事务结束才会释放这些行级锁。在事务A的整个执行过程中,只要其加上行级共享锁后,其它要修改该行数据的事务(需加排它锁)都要处于挂起等待状态。在这种隔离级别,会避免上述第1,第2种问题,第3种问题会出现。目前MySQL, InnoDB默认使用这种数据库隔离级别。

4》Serializable:事务A需要读取某张表后,会在该表上加表级锁,并直到事务结束才会释放,期间所有需要修改该表数据的事务都处于挂起等待状态。在这种隔离级别,效率最低,但上述3种问题可以全部在数据库级别避免。目前没有任何数据库系统默认在这个级别上。

在实际情况中,对于数据库级别锁的使用通常会默认到 Read Committed 级别,然后配以乐观锁来达到基本上的Repeatable Read级别。上面提到的所有锁均是数据库系统自身提供的,统称为悲观锁,名字来意大概为:我感觉不好的事一定会发生,我要通过最保险的方式去控制。相对应的就是乐观锁,通常是程序员通过往表中加一列数据再通过代码来实现的。在我所开发的产品中,都是通过ts(时间戳)来实现,也有通过version(版本)列来控制,这个视个人喜好。

对于我的经历,数据库系统设置为Read Committed,事务读取数据,修改数据,在提交数据时,首先检测数据ts和数据库中数据ts是否一致,一致,则允许提交,否则抛异常,回滚事务,因为数据库系统的数据已经被修改,需要用户刷新数据然后再去修改!这样基本能达到Repeatable Read级别。

实际应用中,事务的控制都是放在业务层,因为一个业务可能会涉及多张表的操作,这些所有的数据库操作视为一个事务。有的复杂业务甚至是涉及到多个数据库系统的操作,这就需要分布式事务了,这里单纯依赖数据库系统本身的事务控制已经无法满足要求,需要额外的事务管理器,也涉及了其他很多概念如二阶段提交等。这个实际应用中我也没有使用,希望以后能接触到再和大家分享。