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. QtUI设计:设置控件透明

    QT设置按钮控件透明: 代码: //设置按钮 背景 前景 this->ui->ShowCvRGB->setStyleSheet(QString("color:rgba(25 ...

  2. 安卓多线程——AsyncTask

    在采集视频的同时需要对视频进行实时处理,因此要使用到多线程. AsyncTask是android提供的一个处理异步任务的框架,相当于Handler+Thread.相比而言,AsyncTask的优点是封 ...

  3. VTK初始化New返回Null问题

    原文链接:http://www.cppblog.com/mythma/archive/2013/08/02/vtk-6-new-null.html 在使用VTK6.0时候,会遇到X::New()返回为 ...

  4. BZOJ 1579: [Usaco2009 Feb]Revamping Trails 道路升级 分层图最短路 + Dijkstra

    Description 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M. 道路i连接牛棚P1_i和P2_i ...

  5. Python实现ATM+购物商城

    需求: 模拟实现一个ATM + 购物商城程序 额度 15000或自定义 实现购物商城,买东西加入 购物车,调用信用卡接口结账 可以提现,手续费5% 每月22号出账单,每月10号为还款日,过期未还,按欠 ...

  6. 51nod1081 子段求和

    给出一个长度为N的数组,进行Q次查询,查询从第i个元素开始长度为l的子段所有元素之和. 例如,1 3 7 9 -1,查询第2个元素开始长度为3的子段和,1 {3 7 9} -1.3 + 7 + 9 = ...

  7. Educational Codeforces Round 35 B/C/D

    B. Two Cakes 传送门:http://codeforces.com/contest/911/problem/B 本题是一个数学问题. 有a个Ⅰ类球,b个Ⅱ类球:有n个盒子.将球放入盒子中,要 ...

  8. mysql 基础教程

    创建数据库: CREATE DATABASE --DATABASE 或者 SCHEMA数据库集合 IF NOT EXISTS db_name CHARACTER SET utf8 COLLATE ut ...

  9. 【ZOJ 4062】Plants vs. Zombies

    [链接] 我是链接,点我呀:) [题意] [题解] 二分最后的最大抵御值mid. 然后对于每个蘑菇. 都能算出来它要浇水几次mid/ai 然后如果第i个蘑菇没浇水达到要求次数. 就在i和i+1之间来回 ...

  10. HDU 4528

    一直在纠结怎么样表示找到了人,,,开始时竟灰笨得设两个BOOL.后来参考别人的可以使用二进制位. 另外,此处有一个剪枝就是,就到达该点之后的状态的found(即找到人的状态)在之前已出现过,可以剪去. ...