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. OAuth密码模式说明(resource owner password credentials)

    用户向客户端(third party application)提供用户名和密码. 客户端将用户名和密码发给认证服务器(Authorization server),向后者请求令牌(token). 认证服 ...

  2. rev

    功能说明:反向输出文件内容.   字符串反转   文本反转

  3. (转)OpenLayers3基础教程——OL3基本概念

    http://blog.csdn.net/gisshixisheng/article/details/46756275 OpenLayers3基础教程——OL3基本概念 从本节开始,我会陆陆续续的更新 ...

  4. Dart 调用C语言混合编程

    Dart 调用C语言本篇博客研究Dart语言如何调用C语言代码混合编程,最后我们实现一个简单示例,在C语言中编写简单加解密函数,使用dart调用并传入字符串,返回加密结果,调用解密函数,恢复字符串内容 ...

  5. 【剑指Offer】3、从尾到头打印链表

      题目描述:   输入一个链表,按链表值从尾到头的顺序返回一个ArrayList.   解题思路:   (三种方法:借助栈.递归.列表的首位插入)   从头到尾打印链表比较简单,从尾到头很自然的可以 ...

  6. 11.7 【Linq】在查询表达式和点标记之间作出选择

    11.7.1 需要使用点标记的操作 最明显的必须使用点标记的情形是调用 Reverse . ToDictionary 这类没有相应的查询表达式语法的方法.然而即使查询表达式支持你要使用的查询操作符,也 ...

  7. 博弈论题目总结(二)——SG组合游戏及变形

    SG函数 为了更一般化博弈问题,我们引入SG函数 SG函数有如下性质: 1.如果某个状态SG函数值为0,则它后继的每个状态SG函数值都不为0 2.如果某个状态SG函数值不为0,则它至少存在一个后继的状 ...

  8. [POI2010] Intelligence test

    yyl说是用链表O(n)做 但是并脑补不出来. 发现可以用个vector记录一下每个数出现的位置,然后对于每个新序列就二分一下,找下一个数出现的离当前位置最近的位置,更新一下当前位置即可. 时间复杂度 ...

  9. linux 中,mysql数据库备份操作

    1.新建一个sh脚本(可以先建一个txt文本,然后改为sh文件). 代码如下: #!/bin/bash #设置mysql备份目录 folder=/**/** cd $folder day=`date ...

  10. JavaScript响应式轮播图插件–Flickity

    简介 flickity是一款自适应手机触屏滑动插件,它的API参数很丰富,包括对齐方式.循环滚动.自动播放.是否支持拖动.是否开启分页.是否自适应窗口等. 在线演示及下载 演示地址 下载页面 使用方法 ...