C#事务处理
一:事物的特点(ACID)
1:原子性,要么全部执行,要么全部不执行
2:一致性
3:隔离性
4:持久性
二:操作事务的典型步骤
1:创建一个Connection对象,建立与数据库的连接
SqlConnection myConnection = new SqlConnection(connectString);
myConnection.Open();
2:使用Connection.BeginTransaction方法创建一个Transaction对象,启动本地事务。
SqlTransaction myTrans = myConnection.BeginTransaction();
3:创建一个Command对象
SqlCommand myCommand = myConnection.CreateCommand();
4:将Transaction对象分配给Command对象的Transaction属性
myCommand.Transaction = myTrans;
5:执行数据库命令
cmd.CommandText = "Insert into...."
cmd.ExecuteNonQuery();
6:根据命令的执行结果调Commit提交事务或Rollback方法取消事务。
myTrans.Commit();
myTrans.Rollback();
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[InsertOrder]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[InsertOrder]
--从当前数据库中删除一个或多个存储过程或过程组。
GO
SET QUOTED_IDENTIFIER OFF
--当 SET QUOTED_IDENTIFIER 为 ON 时,标识符可以由双引号分隔,而文字必须由单引号分隔。
--当 SET QUOTED_IDENTIFIER 为 OFF 时,标识符不可加引号,且必须符合所有 Transact-SQL 标识符规则。
GO
SET ANSI_NULLS OFF
--当设置为 ON 时,所有与空值比较的值都取值为 NULL(未知)。
--当设置为 OFF 时,如果两个值都为 NULL,则非 Unicode 值与空值比较的值都取值为 TRUE。
GO
use northwind
GO
--------------------------------------------------
-- InsertOrder
--------------------------------------------------
CREATE PROCEDURE InsertOrder
@CustomerID nchar(5),
@EmployeeID int,
@OrderDate datetime,
@RequiredDate datetime,
@ShippedDate datetime,
@ShipAddress nvarchar(60),
@Id int OUTPUT
AS
BEGIN TRANSACTION
-- Insert Values into the Orders table
INSERT Into Orders(
CustomerID,
EmployeeID,
OrderDate,
RequiredDate,
ShippedDate,
ShipAddress
)Values(
@CustomerID,
@EmployeeID,
@OrderDate,
@RequiredDate,
@ShippedDate,
@ShipAddress
)
-- Get the new Order Identifier, return as OUTPUT param
SELECT @Id = @@IDENTITY
COMMIT TRANSACTION
RETURN 0
--------------------------------------------------
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO
三:示例
public void RunSqlTransaction(string myConnString)
{
SqlConnection myConnection = new SqlConnection(myConnString);
SqlCommand myCommand = myConnection.CreateCommand();
SqlTransaction myTrans;
myTrans = myConnection.BeginTransaction();
myCommand.Connection = myConnection;
myCommand.Transaction = myTrans;
try
{
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, ´Description´)";
myCommand.ExecuteNonQuery();
myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, ´Description´)";
myCommand.ExecuteNonQuery();
myTrans.Commit();
Console.WriteLine("Both records are written to database.");
}
catch (Exception e)
{
try
{
myTrans.Rollback();
}
catch (SqlException ex)
{
if (myTrans.Connection != null)
{
Console.WriteLine("An exception of type " + ex.GetType() +
" was encountered while attempting to roll back the transaction.");
}
}
Console.WriteLine("An exception of type " + e.GetType() +
" was encountered while inserting the data.");
Console.WriteLine("Neither record was written to database.");
}
finally
{
myConnection.Close();
}
}
==================================================
一:何时使用事务
1:在批处理过程中,必须把多个行为作为一个单元插入或删除
2:只要一个表发生变化,就需要其他表与它同步
3:同时修改两个或多个数据库中的数据
4:在分布式事务中,在不同服务器上操作数据库中的数据
二:ACID属性:原子性,一致性,孤立性和持续性
1:原子性:如果把事务视作单一动作而非各个操作的集合,则它是原子事务。
只有当所有操作都成功时,事务才成功,并且才会把它提交给数据库。
如果在事务处理期间有一个操作失败,则认为所有操作都失败,如果操作已经执行,则撤销或回滚。
2:一致性:事务无论是否成功的完成,都应该让数据库处于一致状态。
由事务修改的数据必须符合设置在列上的所有约束,以保持数据的完整性。
3:孤立性:每个事务都有明确定义的界限。
一个事务不应该影响同时运行的其他事务。
一个事务完成的数据修改必须独立于其他事务完成的数据修改。
事务要么看到另一并发事务之前处于原来状态的数据,要么看到第二个事务结束后的数据,但看不到中间状态。
4:持续性:发生在成功事务内的数据修改将永久保存在系统内,与它们发生的时间无关。
维护事务日志,如果出现故障,就可以把数据库恢复到其原来的状态。
完成每个事务时,都在数据库事务日志内对其进行记录。
如果存在一个主要的系统故障,要求数据库从备份中恢复,将使用这个事务日志插入已经发生的任何成功事务。
三:编写事务的准则
1:在事务中不需要用户输入
2:如果可能,不要再浏览数据的时候打开事物
3:尽量使事物简短
4:在事物中最小化访问数据
四:在T-SQL中编写事务
CREATE PROCEDURE sp_Trans_Test
@newcustid nchar(5), --三个局部变量
@newcompname nchar(40),
@oldcustid nchar(5)
AS
DECLARE @inserr int
DECLARE @delerr int
DECLARE @maxerr int
SET @maxerr = 0
BEGIN TRANSACTION
INSERT into customers(customerid, companyname) VALUES(@newcustid, @newcompname)
SET @inserr = @@error --保存语句操作的返回结果
IF(@inserr > @maxerr)
SET @maxerr = @inserr
DELETE FROM customers WHERE customerid = @oldcustid
SET @delerr = @@error --保存语句操作的返回结果
IF(@delerr > @maxerr)
SET @maxerr = @delerr
IF(@maxerr <> 0)
BEGIN
ROLLBACK
PRINT 'Transaction rolled back'
END
ELSE
BEGIN
COMMIT
print 'Transaction committed'
END
PRINT 'INSERT error number:' + CAST(@inserr AS NVARCHAR(8))
PRINT 'DELETE error number:' + CAST(@delerr AS NVARCHAR(8))
return @maxerr;
1: EXEC sp_Trans_Test 'dd','dd','z'
(1 行受影响)
(0 行受影响)
Transaction committed
INSERT error number:0
DELETE error number:0
2: EXEC sp_Trans_Test 'dd','dd','z'
The statement has been terminated.
(0 行受影响)
Transaction rolled back
INSERT error number:2627
DELETE error number:0
五:在ADO.NET中编写事务
SqlConnection conn = new SqlConnection(@"server=./sqlexpress; integrated security=true; database=northwind");
String sqlins = @"INSERT into customers(customerid, companyname) VALUES(@newcustid, @newcompname)";
String sqldel = @"DELETE FROM customers WHERE customerid = @oldcustid";
SqlTransaction sqltrans = null;
try
{
conn.Open();
sqltrans = conn.BeginTransaction();
SqlCommand cmdins = conn.CreateCommand();
cmdins.CommandText = sqlins;
cmdins.Transaction = sqltrans;
cmdins.Parameters.Add("@newcustid", System.Data.SqlDbType.NVarChar, 5);
cmdins.Parameters.Add("@newcompname", System.Data.SqlDbType.NVarChar, 30);
cmdins.Parameters["@newcustid"].Value = textBox1.Text;
cmdins.Parameters["@newcompname"].Value = textBox2.Text;
SqlCommand cmddel = conn.CreateCommand();
cmddel.CommandText = sqldel;
cmddel.Transaction = sqltrans;
cmddel.Parameters.Add("@oldcustid", System.Data.SqlDbType.NVarChar, 5);
cmddel.Parameters["@oldcustid"].Value = textBox3.Text;
cmdins.ExecuteNonQuery();
cmddel.ExecuteNonQuery();
sqltrans.Commit();
MessageBox.Show("transaction committed");
}
catch(Exception ex)
{
sqltrans.Rollback();
conn.Close();
}