一、数据库事务
1、事务是作为单个逻辑工作单元执行的一系列操作。可以是一条SQL语句也可以是多条SQL语句。
2、事务具有四个特性
原子性:不可分隔、成则具成、败则具败。
恢滦裕菏挛裨谕瓿墒保 匦胧顾 械氖 荻急3忠恢伦刺?
隔离性:独立的执行互不干扰。由并发事务所作的修改必须与任何其他并发事务所作的修改隔离(另外的描述:多个事务同时进行,它们之间应该互不干扰.应该防止一个事务处理其他事务也要修改的数据时,不合理的存取和不完整的读取数据)
3、启动事务:使用 API 函数和 Transact-SQL 语句,可以按显式、自动提交或隐式的方式来启动事务。
4、结束事务:您可以使用 COMMIT(成功) 或 ROLLBACK(失败) 语句,或者通过 API 函数来结束事务。
5、创建事务的原则:
尽可能使事务保持简短很重要,当事务启动后,数据库管理系统 (DBMS) 必须在事务结束之前保留很多资源、以保证事务的正确安全执行。
特别是在大量并发的系统中, 保持事务简短以减少并发 资源锁定争夺,将先得更为重要。
1、事务处理,禁止与用户交互,在事务开始前完成用户输入。
2、在浏览数据时,尽量不要打开事务
3、尽可能使事务保持简短。
4、考虑为只读查询使用快照隔离,以减少阻塞。
5、灵活地使用更低的事务隔离级别。
6、灵活地使用更低的游标并发选项,例如开放式并发选项。
7、在事务中尽量使访问的数据量最小。
二、事务的隔离级别
1、数据库事务的隔离级别:四种
隔离级别 | 脏读(Dirty Read) | 不可重复读(NonRepeatable Read) | 幻读(Phantom Read) |
读未提交(Read uncommitted) |
可能 |
可能 |
可能 |
读已提交(Read committed) |
不可能 |
可能 |
可能 |
可重复读(Repeatable read) |
不可能 |
不可能 |
可能 |
可串行化(Serializable ) |
不可能 |
不可能 |
不可能 |
2、数据库一般的默认隔离离级别是“读已提交”,默认的事务隔离级别下:Insert,update ,delete下的是X锁, 会等待事务完成。通常情况下可以把隔离级别设为Read Commited,它能避免脏读,而且有较好的并发性能。尽管它会导致不可重复读、虚读和第二类更新丢失等问题,在可能出现这类问题的个别场合可以由应用程序釆用悲观锁或乐观锁来控制。
3、SQL语句可以使用SET TRANSACTION ISOLATION LEVEL来设置事务的隔离级别。如:SET TRANSACTION ISOLATION LEVEL Read Committed。若要在应用程序中使用更严格或较宽松的隔离级别,可以通过使用 set transaction isolation level语句设置会话的隔离级别,来自定义整个会话的锁定。
指定隔离级别后,sql server会话中所有select语句的锁定行为都运行于该隔离级别上,并一直保持有效直到会话终止或者将隔离级别设置为另一个级别。
4、另外要提一点:SQL标准对事务隔离级别的规定,是按该级别不可能发生什么问题来确定的,不一定会发生这样的问题;所以,不同的数据库对事务隔离的级别约定不一样,比如,有的数据库把 可重复读级别按可串行化来对待。(lkdlhw_2000个人理解:各个数据库应该都遵循四种标准的事务隔离等级的定义,但是某些数据库具体实现可能不存在四种,因为串行化可以避免不可重复读,因此某些数据库语法上支持设置事务隔离等级为不可重复读,但实际上是串行化在起作用。也就是说只要该级别能够避免不可重复读的问题,就可以称之为不可重复读取级别。)
5、该隔离级别定义一个事务必须与其他事务所进行的资源或数据更改相隔离的程度。事务隔离级别控制:
读取数据时是否占用锁以及所请求的锁类型。
占用读取锁的时间。
引用其他事务修改的行的读取操作是否:
在该行上的排他锁被释放之前阻塞其他事务。
检索在启动语句或事务时存在的行的已提交版本。
读取未提交的数据修改
三、锁
1、分类:从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁
2、事务使用锁,防止其他用户修改另外一个还没有完成的事务中的数据。对于多用户系统来说,锁机制是必须的。SQL Server有多种锁,允许事务锁定不同的资源。锁就是保护指定的资源,不被其他事务操作。SQL Server有多种锁,允许事务锁定不同的资源。锁就是保护指定的资源,不被其他事务操作。为了最小化锁的成本,SQL Server自动地以与任务相应等级的锁来锁定资源对象。锁定比较小的对象,例如锁定行,虽然可以提高并发性,但是却有较高的开支,因为如果锁定许多行,那么需要占有更多的锁。锁定比较大的对象,例如锁定表,会大大降低并发性,因为锁定整个表就限制了其他事务访问该表的其他部分,但是成本开支比较低,因为只需维护比较少的锁。
3、 锁的特点:
1. 锁是保证并发控制的手段
2. 可以锁定的资源包括行、页、簇、表和数据库
3. 锁的类型主要包括共享锁和排它锁
4. 特殊类型的锁包括意图锁、修改锁和模式锁
5. 共享锁允许其他事务继续使用锁定的资源
6. 排它锁只允许一个事务访问数据
7. 系统本身可以处理死锁
8. 用户可以根据实际情况定制锁的一些特征
4、锁是定义到sql语句上的,对数据进行操作的sql就是:select,Insert,update ,delete。不同的事物隔离即被在执行sql的时候会向表上发送不同的锁。
关于锁的更多描述,可以去网上搜索一下。http://www.bitscn.com/windows/sql/200604/1068.html
四、多个用户同时对数据库的并发操作时会带来以下数据不一致的问题:
脏读dirty reads:
当事务读取还未被提交的数据时,就会发生这种事件。举例来说:Transaction1修改了一行数据,然后Transaction2在Transaction1还未提交修改操作之前读取了被修改的行。如果Transaction1回滚了修改操作,那么Transaction2读取的数据就可以看作是从未存在过的。
不可重复的读non-repeatable reads:
当事务两次读取同一行数据,但每次得到的数据都不一样时,就会发生这种事件。举例来说:Transaction1读取一行数据,然后Transaction2修改或删除该行并提交修改操作。当Transaction1试图重新读取该行时,它就会得到不同的数据值(如果该行被更新)或发现该行不再存在(如果该行被删除)。
虚读phantom read:
如果符合搜索条件的一行数据在后面的读取操作中出现,但该行数据却不属于最初的数据,就会发生这种事件。举例来说Transactio1读取满足某种搜索条件的一些行,然后Transaction2插入了符合Transaction1的搜索条件的一个新行。如果Transaction1重新执行产生原来那些行的查询,就会得到不同的行。
为了解决这些问题,数据库引入了“锁”的机制(从数据库系统的角度来看:分为独占锁(即排它锁),共享锁和更新锁,详细内容不再描述)。
五、lkdlhw_2000个人理解(以下问题都是推测,还没有证实):
隔离级别是由锁来实现的,之所以出现事务的隔离级别相当于数据库开发商根据一般的业务需求实现定义好的一组锁使用的规则,便于我们时候,当我们将事务隔离级别定义到某一级上后如果不能满足需求,我们还可以自行定义sql的锁来覆盖事务隔离级别默认的锁机制?
锁存在两个问题:一个是锁的粒度,一个是锁的时间,锁的时间应该包括两种一种是sql执行完就释放锁,领一中是事务结束后释放锁
六、参考文章
http://www.es-ivision.com/Channel-4-10-108-0.html
http://tech.ccidnet.com/art/1105/20050602/261573_1.html
http://www.blogjava.net/zhengtengfeng/archive/2007/04/23/113025.html
七、事务隔离级别的例子
1. Read Uncommitted:最低等级的事务隔离,仅仅保证了读取过程中不会读取到非法数据。上诉4种不确定情况均有可能发生。
2. Read Committed:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。
第一个查询事务
SET TRANSACTION ISOLATION LEVEL Read Committed
begin tran
update Cate SET Sname=Sname+'b' where ID=1
SELECT * FROM cate where ID=1
waitfor delay '00:00:6'
rollback tran --回滚事务
select Getdate()
SELECT * FROM cate where ID=1
第二个查询事务
SET TRANSACTION ISOLATION LEVEL Read committed --把committed换成Read uncommitted可看到“脏读取”的示例。
SELECT * FROM cate where ID=1
select Getdate()
可以看到使用 Read Committed 成功的避免了“脏读取”.
3. Repeatable Read:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。
第一个查询事务
SET TRANSACTION ISOLATION LEVEL Repeatable Read -- 把Repeatable Read换成Read committed可以看到“不可重复读取”的示例
begin tran
SELECT * FROM cate where ID=33 --第一次读取数据
waitfor delay '00:00:6'
SELECT * FROM cate where ID=33 --第二次读取数据,不可重复读取
commit
第二个查询事务
SET TRANSACTION ISOLATION LEVEL Read committed
update cate set Sname=Sname+'JD' where ID=33
SELECT * FROM cate where ID>30
4. Serializable:最高等级的事务隔离,上面3种不确定情况都将被规避。这个级别将模拟事务的串行执行。
在第一个查询窗口执行
SET TRANSACTION ISOLATION LEVEL Serializable -- 把Serializable换成Repeatable Read 可看到“幻像读”的示例
begin tran
SELECT * FROM cate where ID>30 --第一次读取数据,“幻像读”的示例
waitfor delay '00:00:6' --延迟6秒读取
SELECT * FROM cate where ID>30 --第一次读取数据
commit
第二个查询事务
SET TRANSACTION ISOLATION LEVEL Read committed
Delete from cate where ID>33
SELECT * FROM cate where ID>30
创建事务
设置事务级别:SET TRANSACTION ISOLATION LEVEL
开始事务:begin tran
提交事务:COMMIT
回滚事务:ROLLBACK
创建事务保存点:SAVE TRANSACTION savepoint_name
回滚到事务点:ROLLBACK TRANSACTION savepoint_name
1、并发的影响:
http://technet.microsoft.com/zh-cn/library/ms190805.aspx 该文章列出了并发引起的四种影响:丢失更新、脏读(未提交的依赖关系)、不可重复读(不一致的分析)、幻读
2、并发控制类型:
http://technet.microsoft.com/zh-cn/library/ms189132.aspx 当许多人试图同时修改数据库中的数据时,必须实现一个控制系统,使一个人所做的修改不会对他人所做的修改产生负面影响。这称为并发控制。并发控制类型分为两大类:乐观并发控制和悲观并发控制
3、数据库引擎中的隔离级别:
http://technet.microsoft.com/zh-cn/library/ms189122.aspx 1)讲到了事务隔离级别控制的内容:
事务隔离级别控制:
读取数据时是否占用锁以及所请求的锁类型。
占用读取锁的时间。
引用其他事务修改的行的读取操作是否:
在该行上的排他锁被释放之前阻塞其他事务。
检索在启动语句或事务时存在的行的已提交版本。
读取未提交的数据修改。
2)列出了事务的隔离级别:
未提交读(隔离事务的最低级别,只能保证不读取物理上损坏的数据)
已提交读(数据库引擎的默认级别)
可重复读
可序列化(隔离事务的最高级别,事务之间完全隔离)
3)选择事务隔离级别不影响为保护数据修改而获取的锁。事务总是在其修改的任何数据上获取排他锁并在事务完成之前持有该锁,不管为该事务设置了什么样的隔离级别。对于读取操作,事务隔离级别主要定义保护级别,以防受到其他事务所做更改的影响。
4、SET TRANSACTION ISOLATION LEVEL (Transact-SQL) 设置事务隔离级别
http://technet.microsoft.com/zh-cn/library/ms173763.aspx 该选项的作用与在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK 相同
5、总结:
通过以上几篇文章基本上可以了解数据库事务和锁之间的关系。数据库事务隔级别也是由锁机制来最实现的。要想了解关于锁的更深层析的内容还需要专门学习锁的相关知识。