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. SLAM: 图像角点检测的Fast算法(时间阈值实验)

    作为角点检测的一种快速方法,FastCornerDetect算法比Harris方法.SIft方法都要快一些,应用于实时性要求较高的场合,可以直接应用于SLAM的随机匹配过程.算法来源于2006年的Ed ...

  2. spring IOC bean中注入bean

    俩个实体 package com.java.test4; /** * @author nidegui * @create 2019-06-22 14:45 */ public class People ...

  3. MySQL NULL 值如何处理?

    我们已经知道 MySQL 使用 SQL SELECT 命令及 WHERE 子句来读取数据表中的数据,但是当提供的查询条件字段为 NULL 时,该命令可能就无法正常工作. 为了处理这种情况,MySQL提 ...

  4. mysql1064问题完美解决

    1.mysql报错code代表具体意思 1005:创建表失败 1006:创建数据库失败 1007:数据库已存在,创建数据库失败 1008:数据库不存在,删除数据库失败 1009:不能删除数据库文件导致 ...

  5. esp32(M5STACK)在线体验(Ubuntu)

    我们往m5stack烧录的固件是可以在线编程的 具体使用方法可以参考   https://github.com/m5stack/M5Cloud/blob/master/README_CN.md     ...

  6. 11.【Linq】

    11.2.4  Cast . OfType 和显式类型的范围变量 这两个操作符很相似:都可以处理任意非类型化的序列(它们是非泛型 IEnumerable 类的扩展方法),并返回强类型的序列. Cast ...

  7. Windows下Jupyter notebook 修改默认打开(工作、保存)文件夹(路径)

    今天晚上兴致一起突然想看看我写了那么多的ipynb文件都去哪了 首先查了一下,应该是都默认保存到    C:\Users\芩溪儿   路径下了 然后我就想,我是不是得改改啊,总在那跟别的文件夹在一起总 ...

  8. 教你 Shiro + SpringBoot 整合 JWT

    本篇文章将教大家在 shiro + springBoot 的基础上整合 JWT (JSON Web Token) 如果对 shiro 如何整合 springBoot 还不了解的可以先去看我的上一篇文章 ...

  9. orcale 基本查询(1)

    orcale 基本查询 查询当前用户下的所有表:  select * from tab; 查询表结构: desc 表名设置行宽: set linesize 120;设置列宽: 数值类型: col 列名 ...

  10. 运行npm run watch时报:events.js:182 throw er; // Unhandled 'error' event

    I had this issue i did the following steps and i have no issues anymore: Delete node_modules directo ...