C#中批量处理数据,有时候因为一条记录导致整个批量处理失败。这时候肯能会导致数据不全等问题,这时候我们可以使用SqlTransaction来进行事务回滚,即是要么全部成功要么全部不成功。如下代码

  //测试事务回滚
public static string GetMsgBySJ()
{
var msg = "";
SqlConnection conn = new SqlConnection(connStr);
SqlCommand cmd = conn.CreateCommand();
conn.Open();//打开之后开启事务
SqlTransaction tran = conn.BeginTransaction();//开启事务
cmd.Transaction = tran;//将事务应用于CMD
try
{
cmd.CommandText = " INSERT into t_student VALUES ('huage1','11','男神') ";
cmd.ExecuteNonQuery();
cmd.CommandText = " INSERT into t_student VALUES ('huage','11','女神','') ";
cmd.ExecuteNonQuery();
tran.Commit();//提交事务(不提交不会回滚错误)
msg = "插入成功";
}
catch (Exception ex)
{
tran.Rollback();
msg = "插入失败,事物回滚";
}
finally
{
conn.Close();
conn.Dispose();
cmd.Dispose();
tran.Dispose();
}
return msg;
}

上面测试代码,INSERT into t_student VALUES ('huage1','11','男神')这条记录其实已经插入数据库,但是因为下条语句操作失败导致插入数据错误,这时候这个Rollback()函数会将数据库表中的数据还原到操作表之前,

也就是说第一条执行成功的语句也会被删掉(如果有自增Id的话,可以去数据库中再插入数据查看Id是否不再连续)。

  下面在介绍一个SqlBulkCopy批量快速插入数据的方法,如果数据量大的话用循环语句进行数据的插入那肯定会使程序变的巨慢,这时候使用SqlBulkCopy来进行插入数据的话就会显得很优越

下面以插入10000行数据做测试。

 //批量将数据导入目的表
public static void DtDrTable(DataTable dt, string tableName)
{
try
{
//这边可以使用事务回滚机制
SqlBulkCopy bcp = new SqlBulkCopy(connStr);
//指定目标数据库的表名
bcp.DestinationTableName = tableName;
//每一批次的行数
bcp.BatchSize = * ;
//建立数据源表字段和目标表中的列之间的映射
//----既然dt的列名需要与表明完全一致,直接循环dt的列即可----//
foreach (DataColumn dc in dt.Columns)
bcp.ColumnMappings.Add(dc.ColumnName, dc.ColumnName);
//写入数据库表 dt 是数据源DataTable
bcp.WriteToServer(dt);
//关闭SqlBulkCopy实例
bcp.Close();
}
catch (Exception ex)
{
throw ex;
}
}

使用SqlBulkCopy进行数据插入的时候,要使得DataTable中的列名,类型与数据库表要完全一致(除了自增Id),下面是调用上面方法的例子

 Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
DataTable dtTemp = new DataTable();
DataColumn[] columns = new DataColumn[]
{
new DataColumn("Name",typeof(string)),
new DataColumn("Age",typeof(Int32)),
new DataColumn("Sex",typeof(string)),
new DataColumn("test",typeof(string)),
};
dtTemp.Columns.AddRange(columns);
//构造一个10000行的DataTable
for (var i = ; i < * ; i++)
{
var n_row = dtTemp.NewRow();
var tt = i + ;
n_row["Name"] = "Name" + tt;
n_row["Age"] = tt;
n_row["Sex"] = "Sex" + tt;
n_row["test"] = "test" + tt;
dtTemp.Rows.Add(n_row);
}
stopWatch.Stop();
Console.WriteLine("构造一万行的Datatable所需时间:" + stopWatch.Elapsed); Stopwatch stopwatcj = new Stopwatch();
stopwatcj.Start();
DtDrTable(dtTemp, "t_student");
stopwatcj.Stop();
Console.WriteLine("10000行数据批量插入表中所需时间:" + stopwatcj.Elapsed);

执行上述测试代码的控制台程序,结果如下:

甚至一秒时间都没到,在内存中构建内存表虽然更快,但是很费内存

  下面展示一个可回滚的批量插入(暂时未测试)

        //批量将数据导入目的表可回滚
public static void TranBatchImportData(DataTable dt, string tableName)
{
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
SqlTransaction tran = conn.BeginTransaction();
using (SqlBulkCopy sqlBC = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, tran))
{
sqlBC.BatchSize = * ;
//sqlBC.BulkCopyTimeout = 60;//超时之前操作完成所允许的秒数
sqlBC.DestinationTableName = tableName;
foreach (DataColumn dc in dt.Columns)
sqlBC.ColumnMappings.Add(dc.ColumnName, dc.ColumnName); sqlBC.WriteToServer(dt);
tran.Commit();
}
}
}

之前在博问中有人提问:有三个不同操作的数据的方法,又不能修改方法,调用的时候能不能加个相当于全局事务锁,就是这三个方法要么全部执行,要么你全部不执行。

下面有人提供的解决方案,使用 System.Transactions.TransactionScope ,这个事务可以实现。

然后我就Mark了一波,写了个例子看看。

  static void Test()
{
//var transactionOption = new TransactionOptions();
////设置事务隔离级别
//transactionOption.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
//// 设置事务超时时间为60秒
//transactionOption.Timeout = new TimeSpan(0, 0, 60);
using (System.Transactions.TransactionScope scope =
new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions
{
IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted,
Timeout = new TimeSpan(0, 0, 120)
}))
{
try
{
ExecuteSql(
"INSERT INTO [user]([id], [name], [age], [password]) VALUES (5, N'zhaoliu', 17, '789');");
ExecuteSql(
"INSERT INTO [user]([id], [name], [age], [password]) VALUES (5, N'zhaoliu', 17, '789');");
ExecuteSql(
"INSERT INTO [user]([id], [name], [age], [password]) VALUES (5, N'zhaoliu', 17, '789');");
ExecuteSql(
"INSERT INTO [user]([id], [name], [age], [password]) VALUES (5, N'zhaoliu', 17, '789');");
ExecuteSql(
"INSERT INTO [user]([id], [name], [age], [password]) VALUES (5, N'zhaoliu', 17, '789');");
ExecuteSql("delete from [user] where id=5;");
ExecuteSql(
"INSERT INTO [user]([id], [name], [age], [password]) VALUES (5, N'zhaoliu', 17, '789',123);");//错误方法
scope.Complete();
}
catch (Exception ex)
{ Console.WriteLine(ex);
}
}
}

  的确是可以实现集中方法之间实现事务。

C#使用SqlTransaction事务回滚与SqlBulkCopy批量插入数据的更多相关文章

  1. sql 中的Bulk和C# 中的SqlBulkCopy批量插入数据 ( 回顾 and 粗谈 )

    通常,我们会对于一个文本文件数据导入到数据库中,不多说,上代码. 首先,表结构如下.   其次,在我当前D盘中有个文本文件名为2.txt的文件. 在数据库中,可以这样通过一句代码插入. Bulk in ...

  2. C#中的SqlBulkCopy批量插入数据

    在C#中,我们可以使用sqlBulkCopy去批量插入数据,其他批量插入方法不在讨论. 1 /// <summary> 2 /// SqlBulkCopy批量插入数据 3 /// < ...

  3. SqlBulkCopy批量插入数据时,不执行触发器和约束的解决方法

    原文:SqlBulkCopy批量插入数据时,不执行触发器和约束的解决方法 在new SqlBulkCopy对象的时候,设置一下SqlBulkCopyOptions选项即可,按位或运算 SqlBulkC ...

  4. 用SqlBulkCopy批量插入数据到SqlServer数据库表中

    首先创建一个数据库连接类:SQLHelper using System; using System.Collections.Generic; using System.Linq; using Syst ...

  5. MSSQL使用sqlbulkcopy批量插入数据

    具体代码如下: /// <summary> /// 批量插入数据到BayonetZipFailedPic表 /// </summary> /// <param name= ...

  6. 使用 SqlBulkCopy 批量插入数据

    /// <summary> /// 使用SqlBulkCopy将DataTable中的数据批量插入数据库中 /// </summary> /// <param name= ...

  7. 使用事务和SqlBulkCopy批量插入数据

    SqlBulkCopy是.NET Framework 2.0新增的类,位于命名空间System.Data.SqlClient下,主要提供把其他数据源的数据有效批量的加载到SQL Server表中的功能 ...

  8. 使用SqlBulkCopy批量插入数据

    static void Main(string[] args) { //定义与目标表结构相同的DataTable DataTable dataTable = new DataTable(); data ...

  9. sqlbulkcopy 批量插入数据

    批量插入 Datetable数据  通过sqlbulkcopy 插入1百万条数据 用时 10秒钟 (有兴趣的小伙伴可以去测试) /// <summary> /// /// </sum ...

随机推荐

  1. [Intermediate Algorithm] - Arguments Optional

    题目 创建一个计算两个参数之和的 function.如果只有一个参数,则返回一个 function,该 function 请求一个参数然后返回求和的结果. 例如,add(2, 3) 应该返回 5,而 ...

  2. nginx设置跳转https

    在监听80端口的内部,添加一句代码:rewrite ^(.*)$ https://$host$1 permanent;

  3. node jsonwebtoken

     jsonwebtoken是node版本的JWT(JSON Web Tokens)的实现.1.什么是JWT?Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于J ...

  4. console.log、toString方法与js判断变量类型

    Java调用system.print.out()是会调用toString方法打印js里的console.log也是控制台打印,很多时候,我们以为也是调用toString方法,其实并不是.我们在chro ...

  5. Js封装html的一些代码

    tableHtml += "<td align=\"left\"><a href=\"javascript:topInfoMenu('&quo ...

  6. SPLAY or SPALY ?

    写在前面: 由我们可爱的Daniel Sleator和Robert Tarjan提出的一种数据结构,平衡树的一种,本质是二叉树. 至于到底是splay还是spaly,我认为可能splay更对一些 毕竟 ...

  7. win10、win7 使用centos配置网络,可以让Xshell进行连接,虚拟机进行上网;

    系统:window 10 虚拟机VMware® Workstation 15 Pro Linux版本:CentOS-6.3 前提:关闭防火墙 如果是win7 系统可以不用第八步,如果不行可以试一下第八 ...

  8. 《奋斗吧!菜鸟》 第八次作业:Alpha冲刺 Scrum meeting 5

    项目 内容 这个作业属于哪个课程 任课教师链接 作业要求 https://www.cnblogs.com/nwnu-daizh/p/11012922.html 团队名称 奋斗吧!菜鸟 作业学习目标 A ...

  9. Java 集合之Collection 接口和遍历方法

    这几篇是我按网上的教程来实习的. URL: http://www.cnblogs.com/jbelial/archive/2013/03/27/2981395.html 打代码的感觉挻好的.. 注意在 ...

  10. C#版winform实现UrlEncode

    在Asp.net中可以使用Server.HTMLEncode和Server.URLEncode 将文本或URL的特殊字符编码,但在控制台或Winform程序中没有办法使用到这些方法, 解决办法:右击项 ...