首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET 將純真 IP 資料庫匯入 SQL Server 完整實作

     編輯:ASP.NET 基礎

資料準備與前置作業

純真 IP 資料庫(QQWry.dat)包含約 38 萬筆記錄。需先使用官方查詢工具將其解壓為文字檔,並確保編碼轉為 UTF-8,避免中文亂碼。

整體架構:AJAX 分批非同步匯入

考量龐大資料量,採用前端 AJAX 輪詢、後端分批處理的模式,避免單一請求逾時,並能即時顯示進度。

前端頁面與 JavaScript

頁面包含資料庫連線設定表單、檔案上傳控制項,以及即時日誌顯示區。核心流程:

  1. 使用隱藏 iframe 模擬非同步檔案上傳(上傳完成觸發父頁面 insertIP())。
  2. 呼叫 /do.ashx?action=init 初始化:建立資料表、快取 IP 清單、回傳總筆數。
  3. 遞迴呼叫 /do.ashx?action=insert&num=隨機數 分批寫入,每批預設 300 筆,直到隊列歸零。
function insertIP() {
    log.innerHTML += "開始分析資料…<br />";
    j.ajax.post("/do.ashx?args=ImportIPData&action=init", "",
        function(x) {
            var d = eval(x)[0];
            recordCount = d.count;
            log.innerHTML += "<font color=green>分析成功: 伺服器 " + d.server + ",共 " + recordCount + " 筆</font><br /><div id='recordLog'></div>";
            insert();
        },
        function(x) { log.innerHTML += "<font color=red>異常終止</font>"; }
    );
}

function insert() {
    if (!reLog) reLog = document.getElementById("recordLog");
    var num = Math.floor(Math.random() * 100);
    j.ajax.post("/do.ashx?args=ImportIPData&action=insert", "num=" + num,
        function(x) {
            var d = eval(x)[0];
            reLog.innerHTML = "已寫入 " + (recordCount - d.count) + " 筆,剩餘 " + d.count + " 筆,本批 " + d.insertNum + " 筆";
            if (d.count != 0) insert();
            else reLog.innerHTML = "恭喜,寫入完畢!";
        },
        function(x) { alert(x); }
    );
}

執行畫面1 執行畫面2

後端 Generic Handler (do.ashx)

單一進入點處理三種 action:

  • submit:接收上傳檔案,解析每行(以多空白分隔),存入 HttpRuntime.Cache["ip_data"],並將連線字串、資料表名存入 Session。
  • init:檢查/建立資料表(欄位:sip, eip, area, name),回傳伺服器資訊與總筆數 JSON。
  • insert:從 Cache 取出清單,依 num 參數決定本批筆數,使用參數化 SQL 批次 INSERT,完成後移除已寫入項目,回傳剩餘筆數。
public void ProcessRequest(HttpContext context) {
    if (context.Request.RequestType != "POST") return;
    string action = context.Request["action"];

    if (string.IsNullOrEmpty(action) || action == "submit") {
        // 儲存連線字串與資料表名
        var sb = new StringBuilder();
        sb.Append("server=").Append(context.Request["dbserver"])
          .Append(";database=").Append(context.Request["dbname"])
          .Append(";uid=").Append(context.Request["dbuid"])
          .Append(";pwd=").Append(context.Request["dbpwd"]);
        context.Session["ip_dbconnstring"] = sb.ToString();
        context.Session["ip_tablename"] = context.Request["tbname"];

        // 讀取並快取 IP 資料
        var ipList = new List();
        using (var sr = new StreamReader(context.Request.Files[0].InputStream, Encoding.UTF8)) {
            while (sr.Peek() != -1) {
                ipList.Add(Regex.Replace(sr.ReadLine(), @"\s{2,}", " "));
            }
        }
        HttpRuntime.Cache.Insert("ip_data", ipList);

        // 回傳初始資訊並觸發前端插入
        sb.Clear();
        sb.Append("[{server:'").Append(context.Request["dbserver"])
          .Append("',count:").Append(ipList.Count)
          .Append(",insertNum:0,taskNum:0}]");
        context.Session["ip_info"] = sb.ToString();
        context.Response.Write("");
    }
    else {
        using (var conn = new SqlConnection(context.Session["ip_dbconnstring"] as string)) {
            string tbname = context.Session["ip_tablename"] as string;
            if (action == "init") {
                var cmd = new SqlCommand($@"IF NOT EXISTS(SELECT * FROM sysobjects WHERE name='{tbname}' AND xtype='u')
                    CREATE TABLE {tbname}(id BIGINT IDENTITY(1,1) PRIMARY KEY, sip NVARCHAR(15), eip NVARCHAR(15), area NVARCHAR(80), name NVARCHAR(80))", conn);
                conn.Open(); cmd.ExecuteNonQuery();
                context.Response.Write(context.Session["ip_info"]);
            }
            else if (action == "insert") {
                var ipList = HttpRuntime.Cache["ip_data"] as IList;
                int insertNum = int.TryParse(context.Request["num"], out var n) && n > 0 ? n : 300;
                var cmd = new SqlCommand { Connection = conn };
                cmd.Parameters.AddRange(new[] {
                    new SqlParameter("@sip", ""), new SqlParameter("@eip", ""),
                    new SqlParameter("@area", ""), new SqlParameter("@name", "")
                });
                conn.Open();
                for (int i = 0; i < insertNum && i < ipList.Count; i++) {
                    var arr = ipList[i].Split(' ');
                    cmd.CommandText = $@"IF NOT EXISTS(SELECT id FROM {tbname} WHERE sip=@sip AND eip=@eip)
                        INSERT INTO {tbname} VALUES(@sip,@eip,@area,@name)";
                    cmd.Parameters["@sip"].Value = arr[0];
                    cmd.Parameters["@eip"].Value = arr[1];
                    cmd.Parameters["@area"].Value = arr[2];
                    cmd.Parameters["@name"].Value = arr.Length >= 4 ? arr[3] : "";
                    cmd.ExecuteNonQuery();
                    ipList.RemoveAt(i--);
                }
                var sb = new StringBuilder();
                sb.Append("[{count:").Append(ipList.Count)
                  .Append(",insertNum:").Append(insertNum).Append("}]");
                context.Response.Write(sb.ToString());
            }
        }
    }
}

執行結果與效能

38 萬筆資料約 1 小時完成匯入(視資料庫效能而定)。完成後資料表截圖:

資料庫匯入結果

關鍵技術點總結

  • Cache + Session 協作:Cache 存放大量資料列表,Session 存放連線資訊,避免頻繁傳遞。
  • 參數化 SQL:防注入、提升執行計畫重用。
  • 分批遞迴 AJAX:前端輪詢實現長時間任務的進度回報與使用者體驗。
  • 去重邏輯:IF NOT EXISTS 避免重複 IP 區間寫入。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved