記得之前面試別人的時候,我問過這樣的一個面試題:請寫出一條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的都介紹完了,歡迎各位拍磚,也希望大家能完善思路。這些具體的使用場景有抓取外部數據(爬蟲),對實時性要求比較高。