VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 数据库 > sql语句 >
  • sql语句大全之数据库设计与事务处理

事务(transaction)其实就是一序列数据库命令,他们可以组合在一起当做一个单一逻辑单元

在一个事务被标记为完成之前(commited),任何改变可以被回滚(rolled back)

例子:转账,它可以包括(减少发送钱账户的金额量,增加收款人的金额量,给发送方和接收方都增加交易记录)

如果连接被打断,或者说一些操作失败了,所有的操作都需要被回滚

→ Total failure is better than partial failure

 

每一个事务的终止信号都是通过commit或者roll back来传达的,没有commit,我们做出的改变不会被保存

但其实Sesssions都是有自动提交功能(auto-commit)的,也就是任何命令都能被马上提交,不需要roll back和commit,这种auto-commit方式都是被默认的(set sutocommit = 0 关闭autocommit)

→ START TRANSACTION or BEGIN

BEGIN;

UPDATE accounts SET balance = balance - 100.00 WHERE acc_nr = 254231426;

UPDATE accounts SET balance = balance + 100.00 WHERE acc_nr = 676535301;

INSERT INTO transfers (acc_nr, amount, reference) VALUES (254231426, -100.00, ’Dentist’);

INSERT INTO transfers (acc_nr, amount, reference) VALUES (676535301, 100.00, ’John Smith’);

COMMIT;

 

同时事务:

复杂情况:多种同时事务

情况1:按顺序执行事务

  很简单去实行,在一些情况下工作的很好

  但是有时过慢了:

    CPU可以保持空闲当I/O转换过程中,反之亦然

    慢的语句可能会阻碍快的那个

    事务可能需要去等待用户输入

情况2:事务的交错执行

  等待时间一半都减少特别明显了

  在单命令事务中也能进行工作(分裂成多种更小的操作)

  但是难以正确实施进行

  这就是DBMS所做的事

 

ACID规则:

ACID规则是摆正多个并行事务能被可靠处理的一组方法策略

Atomicity:原子性   Consistency:一致性   Isolation:交易之间不被相互作用     Durability:持久性

复杂的是隔离或可串行化的:确保并行执行相当于对某个顺序的顺序执行。

这就是并发控制的全部内容。

注意:为了保持DB编程的可管理性,DBMS确保串行化是至关重要的,想象一下担心其他查询会妨碍运行的任何查询!

 

并发控制:

查询被分成许多较小的操作。

允许对这些操作进行交错。

启用并发性

 

但如果使用相同的数据,则会出现问题。

不能更新(Lost Update)

不好识别(Dirty Reads)

不能一致识别(Inconsistent Reads)

 

并发控制的目的:

允许通用的并发,但禁止危险的相互作用。

 

Lost update:

假设有人花了50,并得到了2000,两个事务是同时发生的

语句则被分成很多带顺序的低级操作:

下面是交错操作:

这种方式下在账户里增加2000的效率丢失了

 

Dirty Reads

当事务读取由另一事务修改的值时,会发生Dirty Reads,但修改不是最终的。

交错操作如下:

返回余额0,即便已经被回滚了

 

Inconsistent Reads

不一致(不可重复)的读取 发生在在另一事务之间改变时读值多次

交错操作如下:

最大余额的账户寻找不到

 

读/写锁

目标:

防止对同一数据的并发访问

但要尽量减少对性能的影响

只在必要时限制以防止问题

 

区分读写操作/访问

交错读取操作是无害的。

交错写入操作会引起问题。

交错读写操作也会引起问题。

 

两种锁:

读锁(又名共享锁)

写锁(又名专用锁)

可以有多个读锁或单个写锁

 

在事务访问数据之前,它必须获取锁,如果不可能,稍后再尝试

锁定可以在不同级别下发生:数据库级,表级,页面级别(最常见),行级

 

数据库级别:只需要单个锁,但不并发

行级:大并发,但需要的锁太多

表和页级锁提供了一个折衷方案

 

多查询事务随时间获取锁,在需要时获得很容易。

但是什么时候释放它们呢?

越快越好并发,但有问题

那么,如果我们释放一个锁,然后又需要它会发生什么?

那么,如果我们释放一个锁,然后需要一个不同的锁会发生什么?

二相锁定协议

成长阶段:获取锁(无锁释放)  收缩阶段:释放锁(没有获得的锁)也就是在事务结束时释放所有锁

防止有问题的操作交错

两阶段锁定(带表级锁):

死锁(Deadlocks)

两个事务可能互相等待释放锁。

  因为两者都在等待,没有一个释放他们的锁。

  也可以发生两个以上的事务,这种僵局被称为僵局。

  两相锁定不能防止死锁

死锁可以用不同的方式处理:

死锁预防:

  如果发生僵局,就采取行动

  可能不必要中止交易

死锁检测:

   如果发生死锁,只能采取行动

  用于检测死锁的开销

额外的问题:饥饿

为了解决死锁,事务需要中止(如果可能的话重新开始)

相同的事务可能会一再中止(它“饿死”了)。

解决方案:总是中止上次提交的事务

  所有的事务都是时间戳的。

  当中止并重新启动时,保留原始时间戳。

 

死锁预防:

等待-死亡方案:

如果T1需要一个T2持有的锁:

(等待)如果T1大于T2,等待锁定被释放。

(死亡)如果T1较小,中止T1并稍后重启。

 

伤口等待方案:如果T1需要一个T2持有的锁:

(受伤)如果T1大于T2,则中止T2并重新启动。

(等待)如果T1较小,等待锁定被释放。

 

两种方案的共同点:

死锁被解决的了

年轻的过程中止了——没有饥饿

即使没有死锁,事务也可能中止

 

死锁检测:

目标:只有死锁发生时才会中止

 

构造和维护等待图

每个事务都是一个节点。

如果Ti在等待Tj持有的锁,则从TI到TJ的有向边。

如果图包含任何循环,则为死锁。如果检测到循环,则中止一个事务以中断循环 例如:最年轻的交易——没有饥饿。

维护等待图和检测周期是昂贵的

最适合于很少并发事务的数据库,或者当重新启动事务是有问题的(例如中间结果已经返回)

 

死锁解析由DBMS处理,但并非所有的实现都能防止饥饿。,频繁死锁减速处理(DBMS可能需要一些帮助)

谨慎地构造交易可以减少僵局:

  提前锁定(在事务开始时),减少锁定操作交错的机会

  以固定顺序获取所有事务的锁,防止死锁,但对于大的代码库是困难的

在每种情况下,都必须声明所需的锁。

DBMS提供用于获取/释放锁的工具

 

DBMSs还允许禁用/减弱锁定,防止/减少死锁,加快查询速度,但能制造出不可复制的讨厌的bugs

在大多数情况下,这是个坏方法!

----------------------------------------------------

频繁类型的死锁:先读取数据,然后更新

许多DBMS提供更新锁来处理这个问题。

只允许读取数据

不能有多个更新锁(或更新+写锁),防止上述类型的死锁

允许单个更新锁+多个读锁,不阻止读写锁定

必须由用户明确声明,例如

 

 

数据库恢复

当事务中止时,必须进行更改。

事务被终止可能由于

  用户发出的显式回滚

  死锁、超时或错误

  数据库管理系统崩溃

在DBMS崩溃的情况下,我们需要确保

  所有未提交的事务都会回滚。

  所有已提交事务的更改被保存。

更新通常只在内存中执行,更快,但在DBMS崩溃期间丢失

 

事务日志

所有数据修改都记录在事务日志中。

  存储“前后”和“后”值

  允许改变颠倒

  必须在数据更改之前发生日志记录。(日志没有变化是可以的,没有日志的更改是坏的)

元数据也存储在事务日志中。

  事务的开始/结束(提交或回滚)

  检查点(从内存保存到磁盘的数据),可以识别哪些更新丢失了

当DBMS崩溃时,重新启动它

  读取事务日志

  标识未提交的事务并将它们滚回。

  识别并重新应用已提交事务的丢失更新

dB以一致状态(原子性)开始。

所有承诺的事务持续(持久性)

 

Summary

事务将数据库命令分组为单元

ACID确保DB相互作用是可靠的

交错操作对性能至关重要。

  为了保证隔离,需要进行并发控制

  锁定数据会导致死锁

  解决僵局的协议(DBMS),

  最小化死锁的技术(用户)

使用事务日志的数据库恢


相关教程