SQL事务的学习
2008-08-01 11:02
134 查看
事务(数据库引擎)
事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务。原子性事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
一致性
事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。
隔离
由并发事务所作的修改必须与任何其他并发事务所作的修改隔离。事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。
持久性
事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。
企业数据库系统(如数据库引擎 实例)有责任提供一种机制,保证每个事务的物理完整性。数据库引擎提供:
锁定设备,使事务保持隔离。
记录设备,保证事务的持久性。即使服务器硬件、操作系统或数据库引擎 实例自身出现故障,该实例也可以在重新启动时使用事务日志,将所有未完成的事务自动地回滚到系统出现故障的点。事务管理特性,强制保持事务的原子性和一致性。事务启动之后,就必须成功完成,否则数据库引擎 实例将撤消该事务启动之后对数据所做的所有修改事务是单个的工作单元。如果某一事务成功,则在该事务中进行的所有数据修改均会提交,成为数据库中的永久组成部分。如果事务遇到错误且必须取消或回滚,则所有数据修改均被清除。
SQL Server 以下列事务模式运行。
自动提交事务
每条单独的语句都是一个事务。
显式事务
每个事务均以 BEGIN TRANSACTION 语句显式开始,以 COMMIT 或 ROLLBACK 语句显式结束。
隐式事务
在前一个事务完成时新事务隐式启动,但每个事务仍以 COMMIT 或 ROLLBACK 语句显式完成。
批处理级事务只能应用于多个活动结果集 (MARS),在 MARS 会话中启动的 Transact-SQL 显式或隐式事务变为批处理级事务。当批处理完成时没有提交或回滚的批处理级事务自动由 SQL Server 进行回滚。
事务并发处理会产生的问题
丢失更新
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题、 每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。
脏读
当第二个事务选择其它事务正在更新的行时,会发生未确认的相关性问题。第二个事务正在读取的数据还没有确认并且可能由更新此行的事务所更改。
不可重复读
当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。不一致的分析与未确认的相关性类似,因为其它事
务也是正在更改第二个事务正在读取的数据。然而,在不一致的分析中,第二个事务读取的数据是由已进行了更改的事务提交的。而且,不一致的分析涉及多次(两次或更多)读取同一行,而且每次信息都由其它事务更改;因而该行被非重复读取。
幻像读
当对某行执行插入或删除操作,而该行属于某个事务正在读取的行的范围时,会发生幻像读问题。事务第一次读的行范围显示出其中一行已不复存在于第二次读或后续读中,因为该行已被其它事务删除。同样,由于其它事务的插入操作,事务的第二次或后续读显示有一行已不存在于原始读中。
事物的一个典型例子
银行业务。事务处理应当包括从一个帐户到另一帐户的转帐过程。这一过程属于事务处理,原因是从某帐户中支出和在另一帐户存入两个动作,必须被作为一个整体来执行——任何一方都不允许失败。在深入研究ADO.NET编程之前,让我们先来看看在SQL中是如何进行事务处理的。
SQL事务处理
SQL允许开发人员使用两个简单的声明来使用事务处理
Begin Transaction (启动事务处理)
Commit Transaction (提交事务处理)
在两条声明中的所有语句都成为事务处理的一部分。命令Begin Transaction位于整个事务处理的起始位置,因此其后的所有命令只有在执行到
命令Commit Transaction时才会被一并执行。ADO.NET方法就这么简单。
ADO.NET事务处理
事务处理需要一个数据库连接以及一个事务处理对象。在SQL Server和ADO.NET中使用事务处理的难点在于SqlTransaction类。此类名称随所使
用的数据库平台的不同而会有一些变化。例如,对于OLEDB数据库来说,事务处理类名为OleDbTransaction。
System.Data.SqlClient namespace包括了SqlTransaction类。此类包括了两个属性:
Connection:指示同事务处理相关联的SqlConnection对象;
IsolationLevel:定义事务处理的IsolationLevel。
属性IsolationLevel是包括如下成员的枚举对象:
Chaos:从高度独立的事务处理中出现的pending changes不能被覆盖;
ReadCommitted:当数据需要被非恶意读取时,采用共享锁定(shared locks),但数据仍然可以在事务处理结束时被更新,这造成了非重复性
的数据读取(nonrepeatable reads)或phantom data的产生;
ReadUncommitted:恶意读取数据是可能发生的,这表示没有使用共享锁定(shared locks),并且没有实现独占锁定(exclusive locks);
RepeatableRead:锁定查询中所用到的所有数据,由此避免其他用户对数据进行更新。在phantom rows仍然可用的状态下,这可以避免非重复
性的数据读取(nonrepeatable reads);
Serialisable:在DataSet中进行范围锁定,由此防止其他用户在事务处理结束之前更新数据或在数据库中插入行;
IsolationLevel定义锁定记录的级别,但这一概念不在本文论述范围之内。对象SqlTransaction也提供了类似的方法。你可以使用以下方法来
进行事务处理:
Commit:提交数据库事务处理;
Rollback:从未决状态(pending state)反转(roll back)事务处理。事务处理一旦被提交后即不能执行此操作;
Save:在事务处理中创建savepoint可以对事务处理的一部分进行反转,并且指定savepoint名称。
学习例子1:
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
DoTran();
Response.Write("事务处理已经成功完成。");
}
//执行事务处理
public void DoTran()
{ //建立连接并打开
SqlConnection myConn=GetConn();
myConn.Open();
SqlCommand myComm=new SqlCommand();
//SqlTransaction myTran=new SqlTransaction();
//注意,SqlTransaction类无公开的构造函数
SqlTransaction myTran;
//创建一个事务
myTran=myConn.BeginTransaction();
try
{
//从此开始,基于该连接的数据操作都被认为是事务的一部分
//下面绑定连接和事务对象
myComm.Connection=myConn;
myComm.Transaction=myTran; //定位到pubs数据库
myComm.CommandText="USE pubs";
myComm.ExecuteNonQuery();//更新数据
//将所有的计算机类图书
myComm.CommandText="UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE 'Pc%'";
myComm.ExecuteNonQuery();
//提交事务
myTran.Commit();
}
catch(Exception err)
{
throw new ApplicationException("事务操作出错,系统信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
private SqlConnection GetConn()
{
string strSql="Data Source=localhost;Integrated Security=SSPI;user id=sa;password=123456";
SqlConnection myConn=new SqlConnection(strSql);
return myConn;
}
}
事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单元必须有四个属性,称为原子性、一致性、隔离性和持久性 (ACID) 属性,只有这样才能成为一个事务。原子性事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。
一致性
事务在完成时,必须使所有的数据都保持一致状态。在相关数据库中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构(如 B 树索引或双向链表)都必须是正确的。
隔离
由并发事务所作的修改必须与任何其他并发事务所作的修改隔离。事务识别数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是第二个事务修改它之后的状态,事务不会识别中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。
持久性
事务完成之后,它对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。
企业数据库系统(如数据库引擎 实例)有责任提供一种机制,保证每个事务的物理完整性。数据库引擎提供:
锁定设备,使事务保持隔离。
记录设备,保证事务的持久性。即使服务器硬件、操作系统或数据库引擎 实例自身出现故障,该实例也可以在重新启动时使用事务日志,将所有未完成的事务自动地回滚到系统出现故障的点。事务管理特性,强制保持事务的原子性和一致性。事务启动之后,就必须成功完成,否则数据库引擎 实例将撤消该事务启动之后对数据所做的所有修改事务是单个的工作单元。如果某一事务成功,则在该事务中进行的所有数据修改均会提交,成为数据库中的永久组成部分。如果事务遇到错误且必须取消或回滚,则所有数据修改均被清除。
SQL Server 以下列事务模式运行。
自动提交事务
每条单独的语句都是一个事务。
显式事务
每个事务均以 BEGIN TRANSACTION 语句显式开始,以 COMMIT 或 ROLLBACK 语句显式结束。
隐式事务
在前一个事务完成时新事务隐式启动,但每个事务仍以 COMMIT 或 ROLLBACK 语句显式完成。
批处理级事务只能应用于多个活动结果集 (MARS),在 MARS 会话中启动的 Transact-SQL 显式或隐式事务变为批处理级事务。当批处理完成时没有提交或回滚的批处理级事务自动由 SQL Server 进行回滚。
事务并发处理会产生的问题
丢失更新
当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题、 每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。
脏读
当第二个事务选择其它事务正在更新的行时,会发生未确认的相关性问题。第二个事务正在读取的数据还没有确认并且可能由更新此行的事务所更改。
不可重复读
当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。不一致的分析与未确认的相关性类似,因为其它事
务也是正在更改第二个事务正在读取的数据。然而,在不一致的分析中,第二个事务读取的数据是由已进行了更改的事务提交的。而且,不一致的分析涉及多次(两次或更多)读取同一行,而且每次信息都由其它事务更改;因而该行被非重复读取。
幻像读
当对某行执行插入或删除操作,而该行属于某个事务正在读取的行的范围时,会发生幻像读问题。事务第一次读的行范围显示出其中一行已不复存在于第二次读或后续读中,因为该行已被其它事务删除。同样,由于其它事务的插入操作,事务的第二次或后续读显示有一行已不存在于原始读中。
事物的一个典型例子
银行业务。事务处理应当包括从一个帐户到另一帐户的转帐过程。这一过程属于事务处理,原因是从某帐户中支出和在另一帐户存入两个动作,必须被作为一个整体来执行——任何一方都不允许失败。在深入研究ADO.NET编程之前,让我们先来看看在SQL中是如何进行事务处理的。
SQL事务处理
SQL允许开发人员使用两个简单的声明来使用事务处理
Begin Transaction (启动事务处理)
Commit Transaction (提交事务处理)
在两条声明中的所有语句都成为事务处理的一部分。命令Begin Transaction位于整个事务处理的起始位置,因此其后的所有命令只有在执行到
命令Commit Transaction时才会被一并执行。ADO.NET方法就这么简单。
ADO.NET事务处理
事务处理需要一个数据库连接以及一个事务处理对象。在SQL Server和ADO.NET中使用事务处理的难点在于SqlTransaction类。此类名称随所使
用的数据库平台的不同而会有一些变化。例如,对于OLEDB数据库来说,事务处理类名为OleDbTransaction。
System.Data.SqlClient namespace包括了SqlTransaction类。此类包括了两个属性:
Connection:指示同事务处理相关联的SqlConnection对象;
IsolationLevel:定义事务处理的IsolationLevel。
属性IsolationLevel是包括如下成员的枚举对象:
Chaos:从高度独立的事务处理中出现的pending changes不能被覆盖;
ReadCommitted:当数据需要被非恶意读取时,采用共享锁定(shared locks),但数据仍然可以在事务处理结束时被更新,这造成了非重复性
的数据读取(nonrepeatable reads)或phantom data的产生;
ReadUncommitted:恶意读取数据是可能发生的,这表示没有使用共享锁定(shared locks),并且没有实现独占锁定(exclusive locks);
RepeatableRead:锁定查询中所用到的所有数据,由此避免其他用户对数据进行更新。在phantom rows仍然可用的状态下,这可以避免非重复
性的数据读取(nonrepeatable reads);
Serialisable:在DataSet中进行范围锁定,由此防止其他用户在事务处理结束之前更新数据或在数据库中插入行;
IsolationLevel定义锁定记录的级别,但这一概念不在本文论述范围之内。对象SqlTransaction也提供了类似的方法。你可以使用以下方法来
进行事务处理:
Commit:提交数据库事务处理;
Rollback:从未决状态(pending state)反转(roll back)事务处理。事务处理一旦被提交后即不能执行此操作;
Save:在事务处理中创建savepoint可以对事务处理的一部分进行反转,并且指定savepoint名称。
学习例子1:
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
DoTran();
Response.Write("事务处理已经成功完成。");
}
//执行事务处理
public void DoTran()
{ //建立连接并打开
SqlConnection myConn=GetConn();
myConn.Open();
SqlCommand myComm=new SqlCommand();
//SqlTransaction myTran=new SqlTransaction();
//注意,SqlTransaction类无公开的构造函数
SqlTransaction myTran;
//创建一个事务
myTran=myConn.BeginTransaction();
try
{
//从此开始,基于该连接的数据操作都被认为是事务的一部分
//下面绑定连接和事务对象
myComm.Connection=myConn;
myComm.Transaction=myTran; //定位到pubs数据库
myComm.CommandText="USE pubs";
myComm.ExecuteNonQuery();//更新数据
//将所有的计算机类图书
myComm.CommandText="UPDATE roysched SET royalty = royalty * 1.10 WHERE title_id LIKE 'Pc%'";
myComm.ExecuteNonQuery();
//提交事务
myTran.Commit();
}
catch(Exception err)
{
throw new ApplicationException("事务操作出错,系统信息:"+err.Message);
}
finally
{
myConn.Close();
}
}
private SqlConnection GetConn()
{
string strSql="Data Source=localhost;Integrated Security=SSPI;user id=sa;password=123456";
SqlConnection myConn=new SqlConnection(strSql);
return myConn;
}
}
相关文章推荐
- sql学习.事务
- ASP.NET 3.5核心编程学习笔记(12):SqlCommand、SqlDataReader、事务
- T-Sql学习(14) - 事务处理
- SQL server学习(四)T-SQL编程之事务、索引和视图
- SQL 事务隔离学习
- Linq to Sql 学习系列之七 并发与事务
- SQL 数据库 学习 034 事务
- SQL学习笔记--事务
- Spring Transaction + MyBatis SqlSession事务管理机制研究学习
- 黑马程序员之ADO.NET学习笔记: SqlTransaction(事务)
- ASP.NET 3.5核心编程学习笔记(23):Linq-to-SQL 数据的更新、事务、存储过程、函数
- PL/SQL学习笔记之事务
- SQL查询艺术学习笔记--SQL事务处理 隔离 锁 与 并发操作
- SQL学习笔记6 视图 存储过程 事务处理
- SQL学习笔记13——事务
- SQL事务与锁定学习笔记(一)
- 【Java EE 学习 29 上】【PL/SQL】【存储过程】【存储函数】【触发器】
- SQL学习笔记--组函数
- SQL:1999基本语法(学习笔记)
- Spring 学习7 -事务