C#结合MsSql,MySql批量插入不重复数据思路
记得之前面试别人的时候,我问过这样的一个面试题:请写出一条sql语句批量插入100条不重复的数据到sql20008数据库中。也不知道是为啥,好多人就直接写"Insert into tb values(val1,val2,val3,...)",然后再加上一句话:放在循环中。我有点纳闷,呵呵。说真的,如果我一开始没有接触到批量数据操作的时候,我想我也会这么写。其实,这个题目我主要是考察面试人员对"insert into ...select..."语句的熟悉情况,至于能不能写出完整正确的sql语句并不重要,重要的是思路。
那么在实际开发中我们对于批量操作数据的思路又是啥了?
1.循环构建sql语句,批量提交。
2.使用SqlBulkCopy类,批量提交数据(缺点:没有好的方法去重复,变态的方法是插入数据之前删除已经存在的并且需要批量插入的数据,然后再提交)。
3.使用sql2008的表变量结合"insert into ...select..."语句,代码构建临时表,然后提交临时表数据。
接下来会重点介绍第3种方法,数据库环境分别是sql2008,mysql5.5.16(安装在centos5.6下)。
一,C#+Sql2008
1.首先需要在数据库中构建"用户自定义表类型"以及"存储过程",截图如下:
sql代码:
CREATE TYPE [dbo].[test] AS TABLE(
[id] [int] NULL
)
create proc [dbo].[sp_test]
@t test readonly
as
begin
INSERT INTO testTb(id)
SELECT id FROM @t
end
注意:我们可以在 insert into...select...from...后面加where条件,视具体情况而定。
2.C#代码,在代码里面首先需要创建一个datatable,然后给datatable赋值,最后创建一个调用存储过程的方法。其中调用的代码可以再一次封装,有兴趣的读者可以自己试试看。
构建表结构:
/// <summary>
/// 构建表结构
/// </summary>
public DataTable GetTestTB()
{
DataTable dt = new DataTable("test");
dt.Locale = System.Globalization.CultureInfo.CurrentCulture;
DataColumnCollection cols = null;
cols = dt.Columns;
cols.Add("Amount", typeof(string));
return dt;
}
赋值:
DataTable amazonTable = amazonDAL.GetAmazonOrderTB();
foreach(KeyValuePair<string,AmazonOrder> amazon in newDic)
{
DataRow row = amazonTable.NewRow();
row["AmazonOrderId"] = amazon.Value.AmazonOrderId;
amazonTable.Rows.Add(row);
}
调用:
public int SaveAmazonOrder(DataTable dt)
{
int rVal = 0;
using (SqlConnection con = new SqlConnection(SqlHelp.ConString))
{
con.Open();
SqlCommand insertCommand = new SqlCommand("sp_AmazonOrder_BulkInsertProc", con);
insertCommand.CommandType = CommandType.StoredProcedure;
SqlParameter Param = insertCommand.Parameters.AddWithValue("@OrderType", dt);
Param.SqlDbType = SqlDbType.Structured;
rVal = insertCommand.ExecuteNonQuery();
con.Close();
}
return rVal;
}
注意:如果想同时提交两个表变量的话可以这样操作
public int TransactionSaveData(DataTable dtTrade,DataTable dtOrder)
{
int rVal = 0;
using (SqlConnection conn = new SqlConnection(SqlHelp.ConString))
{
conn.Open();
SqlTransaction tran = conn.BeginTransaction();
using (SqlCommand command = conn.CreateCommand())
{
try
{
command.Transaction = tran;
int rVal1 = 0;
command.CommandText = "sp_Trade_BulkInsertProc";
command.CommandType = CommandType.StoredProcedure;
SqlParameter Param1 = command.Parameters.AddWithValue("@TradeType", dtTrade);
Param1.SqlDbType = SqlDbType.Structured;
rVal1 = command.ExecuteNonQuery();
command.Parameters.Clear();
int rVal2 = 0;
command.CommandText = "sp_Order_BulkInsertProc";
command.CommandType = CommandType.StoredProcedure;
SqlParameter Param2 = command.Parameters.AddWithValue("@OrderType", dtOrder);
Param2.SqlDbType = SqlDbType.Structured;
rVal2 = command.ExecuteNonQuery();
if (rVal1 >= 0 && rVal2 >= 0)
{
tran.Commit();
rVal = 1;
}
else
{
tran.Rollback();
rVal = 0;
}
}
catch(Exception ex)
{
tran.Rollback();
rVal = 0;
}
finally
{
tran.Dispose();
}
}
}
return rVal;
}
到这里sql版的就结束了,下面介绍mysql版本。
二.C#+mysql数据库
思路:因为mysql没有类似sql2008的表变量功能,所以在批量插入数据的时候用txt作为一层缓冲层,验证数据是否已经存在,然后构建sql语句,最后批量提交sql语句,流程图如下:
此处就不贴具体代码了,具体就是文件操作或者用mencache替代,后面将会具体介绍mencache使用。
关于sql,mysql的都介绍完了,欢迎各位拍砖,也希望大家能完善思路。这些具体的使用场景有抓取外部数据(爬虫),对实时性要求比较高。