c#中SqlTransaction——事务详解
c#中SqlTransaction——事务详解
在进行数据库操作时,为了确保数据的完整性和一致性,我们很可能需要使用事务。而c#中的SqlTransaction类提供了方便的事务处理功能,本文将详细介绍使用SqlTransaction进行事务处理的方法和技巧。
什么是事务?
在数据库中,一个事务(Transaction)是指一系列的数据库操作,这些操作被视为一个单独的工作单元,并且这个工作单元的执行结果要么全部成功,要么全部失败。如果其中任何一个操作失败,那么所有的操作都将被回滚,回到操作之前的状态,这保证了数据的一致性。
如何使用SqlTransaction?
使用SqlTransaction进行事务处理需要以下几个步骤:
-
创建SqlConnection对象,并打开连接。
-
开始SqlTransaction事务,传入SqlConnection对象并指定事务隔离级别。
-
执行一系列的SqlCommand操作。
-
如果所有操作都成功,则提交事务,否则回滚事务。
-
关闭SqlConnection连接。
下面,我们将一步一步地讲解这些步骤。
第一步:创建SqlConnection对象,并打开连接
在使用SqlTransaction之前,我们需要创建SqlConnection对象,并打开连接。创建SqlConnection对象和打开连接的代码如下:
SqlConnection connection = new SqlConnection("server=localhost;database=TestDB;uid=sa;pwd=123456");
connection.Open();
在这里我们以本地的"TestDB"数据库为例,假设用户名为"sa",密码为"123456"。
第二步:开始SqlTransaction事务
开始事务时,我们需要通过SqlConnection.BeginTransaction()方法来创建SqlTransaction对象,并指定事务隔离级别。常用的事务隔离级别有以下几种:
- Unspecified:未指定。
- Chaos:打破现有的锁定,仅它自己在工作。
- ReadUncommitted:不考虑其他会话对数据的更改,将所有未提交的更改均视为已提交。
- ReadCommitted:只读取已提交的数据。
- RepeatableRead:在读取数据期间锁定所读取的数据,即使其他会话对其进行了更改,也将保留当前锁定。
- Serializable:可避免脏阅读(Dirty Read)、不可重复读(Non-repeatable Read)和幻读(Phantom Read)等问题,但同步性较差。
以RepeatableRead为例,代码如下所示:
SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.RepeatableRead);
在这里,我们创建了一个名为transaction的SqlTransaction对象。
第三步:执行SqlCommand操作
在事务开始后,我们需要执行一系列的SqlCommand操作。这些操作可以是Insert、Update、Delete等操作,也可以是存储过程或函数的调用。这里我们以Insert为例,插入的数据如下:
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.Transaction = transaction;
command.CommandText = "INSERT INTO Users (UserName, Password, Email) VALUES (@UserName, @Password, @Email)";
command.Parameters.Add("@UserName", SqlDbType.VarChar, 50).Value = "test1";
command.Parameters.Add("@Password", SqlDbType.VarChar, 50).Value = "123456";
command.Parameters.Add("@Email", SqlDbType.VarChar, 50).Value = "test1@test.com";
command.ExecuteNonQuery();
}
通过SqlCommand对象的属性,我们指定了要执行的SqlCommand操作,并将其绑定到SqlTransaction对象上。
第四步:提交事务或回滚事务
如果所有操作都成功,我们就需要提交事务。在SqlTransaction类中提供了Commit方法来提交事务。代码如下所示:
transaction.Commit();
如果有任何一个操作失败,我们需要回滚事务。在SqlTransaction类中提供了Rollback方法来回滚事务。代码如下所示:
transaction.Rollback();
第五步:关闭SqlConnection连接
在所有操作完成后,我们需要关闭SqlConnection连接:
connection.Close();
示例展示
下面,我们将展示两个使用SqlTransaction的示例。
示例1:转账
假设我们要从账户A向账户B转账,我们需要在一个事务中完成以下两个操作:
- 从账户A中扣除指定的金额。
- 在账户B中增加相同的金额。
下面是示例代码:
using (SqlConnection connection = new SqlConnection("server=localhost;database=TestDB;uid=sa;pwd=123456"))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.Serializable);
try
{
using (SqlCommand commandA = new SqlCommand())
{
commandA.Connection = connection;
commandA.Transaction = transaction;
commandA.CommandText = "UPDATE Accounts SET Balance = Balance - @Amount WHERE AccountId = @AccountId";
commandA.Parameters.Add("@Amount", SqlDbType.Decimal).Value = 100m;
commandA.Parameters.Add("@AccountId", SqlDbType.Int, 4).Value = 1;
commandA.ExecuteNonQuery();
}
using (SqlCommand commandB = new SqlCommand())
{
commandB.Connection = connection;
commandB.Transaction = transaction;
commandB.CommandText = "UPDATE Accounts SET Balance = Balance + @Amount WHERE AccountId = @AccountId";
commandB.Parameters.Add("@Amount", SqlDbType.Decimal).Value = 100m;
commandB.Parameters.Add("@AccountId", SqlDbType.Int, 4).Value = 2;
commandB.ExecuteNonQuery();
}
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
Console.WriteLine(ex.Message);
}
connection.Close();
}
在这个示例中,我们通过两个SqlCommand对象分别对AccountId为1和2的账户进行了更新,通过SqlTransaction对象将它们绑定到一个事务上,保证了操作的原子性,以确保数据的一致性。
示例2:批量插入
假设我们有一个数据量比较大的表,我们需要批量向这个表中插入数据,下面是示例代码:
using (SqlConnection connection = new SqlConnection("server=localhost;database=TestDB;uid=sa;pwd=123456"))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
using (SqlCommand command = new SqlCommand())
{
command.Connection = connection;
command.Transaction = transaction;
command.CommandText = "INSERT INTO Students (Name, Age, Gender) VALUES (@Name, @Age, @Gender)";
command.Parameters.Add("@Name", SqlDbType.VarChar, 50);
command.Parameters.Add("@Age", SqlDbType.Int, 4);
command.Parameters.Add("@Gender", SqlDbType.VarChar, 10);
for (int i = 0; i < 1000; i++)
{
command.Parameters["@Name"].Value = "Student_" + i.ToString();
command.Parameters["@Age"].Value = 20 + i % 10;
command.Parameters["@Gender"].Value = i % 2 == 0 ? "Male" : "Female";
command.ExecuteNonQuery();
}
}
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
Console.WriteLine(ex.Message);
}
connection.Close();
}
在这个示例中,我们通过一个SqlCommand对象,循环地插入了1000条记录,并将其绑定到SqlTransaction对象上,以确保数据的一致性。
总结
在使用SqlTransaction进行事务处理时,我们需要掌握SqlConnection、SqlTransaction和SqlCommand等类的基本用法,并且需要密切关注事务的隔离级别。事务处理是数据库操作中必不可少的一部分,只有通过事务处理技术,才能确保数据的完整性和一致性。