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. 【技术累积】【点】【Java】【12】几种常见编码(持续更新)

    问题描述 有这么一段代码: String question = new String(record.getQuestion().getBytes("iso-8859-1"), &q ...

  2. RN-第三方之react-native-pull 下拉刷新、上拉加载

    有一个很好的下拉刷新.上拉加载库:react-native-pull地址:https://github.com/greatbsky/react-native-pull-demo 使用 import { ...

  3. webpack核心提炼

    基本是学习的时候在网上整理的资料,并非自己原创,这篇文章的的主要目的是记录webpack.config.js的配置方式.可能也有不少错误,欢迎指正!! 一.应用场景 前端模块化开发.功能拓展.css预 ...

  4. linux中tomcat启动脚本:关闭、发布、重启、测试是否成功

    说明 在使用jenkins持续集成时,需要实现自动发布包到tomcat.该脚本实现了在jenkins将包发送到linux服务器上后的自动关闭.发布.启动.测试启动是否成功的过程 思路 该思路以tomc ...

  5. 【airtest, python】报错:requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(54, 'Connection reset by peer')),解决方法如下

    环境及设备 mac, xcode , iphonex 问题 最近出现一个让人费解的问题,airtest 没跑多长时间,服务就断掉,而且总是报“requests.exceptions.Connectio ...

  6. Day 23 类的继承,派生,组合,菱形继承,多态与多态性

    类的继承 继承是一种新建类的方式,新建的类称为子类,被继承的类称为父类 继承的特性是:子类会遗传父类的属性 继承是类与类之间的关系 为什么用继承 使用继承可以减少代码的冗余 对象的继承 python中 ...

  7. 在oracle中将某个字段的数据作为列名的查询

    原表结构 查询语句: select sno,sname,sum(语文) 语文,sum(数学) 数学,sum(英语) 英语 from (select sno,sname,decode(subjiect, ...

  8. Linux系统下打印第n行的方法

    方法一:cat cat filename | head -n 5 | tail -n +5 方法二:sed sed -n '5p' filename 扩展:打印第3~5行 cat filename | ...

  9. MyBatis之java.lang.UnsupportedOperationException异常解决方案

    今天在使用MyBatis执行sql语句时,出现如下异常: 执行的sql语句配置信息如下: <select id="getColumnsByTableName" paramet ...

  10. [Angular] Upgrading to RxJS v6

    This is just a learning blog post, check out the talk. 1. Custom pipeable operators: Custom pipeable ...