You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET C# Excel导入SQL Server异常后的数据回滚解决方案咨询

解决Excel导入SQL Server时异常数据回滚的问题

你的问题核心是缺少数据库事务控制——当前代码每执行一次bll.Add(model)就会独立提交一次数据到数据库,一旦中间抛出异常,已经执行的插入操作无法撤销。要实现异常时回滚到导入前的状态,我们需要用数据库事务把所有插入操作包裹起来,确保要么全部成功提交,要么全部失败回滚。

具体实现步骤:

  1. 开启数据库事务:在读取Excel数据之后、开始循环插入之前,创建数据库连接并开启事务。
  2. 让BLL层支持事务:修改你的bll.Add方法,允许传入SqlTransaction参数,确保所有插入操作都在同一个事务中执行。
  3. 事务的提交与回滚:如果所有插入都成功,提交事务;如果中途抛出异常,立即回滚事务,撤销所有已执行的插入操作。

修改后的完整代码示例:

protected void Upad_Click(object sender, EventArgs e)
{
    // 声明数据库连接和事务对象
    SqlConnection conn = null;
    SqlTransaction tran = null;
    try
    {
        string fileFullname = this.FileUpload1.FileName;
        string dataName = DateTime.Now.ToString("yyyyMMddhhmmss");
        string fileName = fileFullname.Substring(fileFullname.LastIndexOf("\\") + 1);
        string type = fileFullname.Substring(fileFullname.LastIndexOf(".") + 1);
        if (type.Equals("xlsx", StringComparison.OrdinalIgnoreCase) || type.Equals("xls", StringComparison.OrdinalIgnoreCase))
        {
            string savePath = Server.MapPath("upfiles/") + "\\" + dataName + "." + type;
            this.FileUpload1.SaveAs(savePath);
            string ProImg = Server.MapPath("./") + "upfiles\\" + dataName + "." + type;
            DataTable dt = ReadExcel(ProImg, 0);

            // 初始化数据库连接和事务(替换成你的数据库连接字符串)
            string connStr = ConfigurationManager.ConnectionStrings["YourConnString"].ConnectionString;
            conn = new SqlConnection(connStr);
            conn.Open();
            tran = conn.BeginTransaction(); // 开启事务

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                model.orgid = dt.Rows[i]["X1"].ToString() + "00"; // 修正原代码的ToString位置错误
                model.orgname = dt.Rows[i]["X2"].ToString();
                model.Unumber = dt.Rows[i]["X3"].ToString();
                model.percode = dt.Rows[i]["X4"].ToString();
                model.pername = Convert.ToString(getleftid.catetype(dt.Rows[i]["X5"].ToString(), 1));
                model.perdate = Convert.ToDateTime(dt.Rows[i]["X6"].ToString());
                model.pernum = Convert.ToDecimal(dt.Rows[i]["X7"]);
                model.addname = Request.Cookies["Admin"].Value.ToString();
                model.addtime = DateTime.Now;
                
                // 将事务传入BLL的Add方法,确保插入操作在事务内执行
                bll.Add(model, tran);
            }

            // 所有数据插入成功,提交事务
            tran.Commit();
            Response.Write("<script language='javascript'>alert('成功导入 " + dt.Rows.Count + " 条数据!');</script>");
            init();
        }
        else
        {
            Response.Write("<script language='javascript'>alert('请上传xlsx或xls格式的文件!');</script>");
        }
    }
    catch(Exception ex)
    {
        // 发生异常,回滚事务
        if (tran != null)
        {
            tran.Rollback();
        }
        // 可以在这里记录异常日志,方便后续排查问题
        // LogHelper.Error("导入Excel失败:" + ex.Message);
        Response.Write("<script language='javascript'>alert('导入失败!原因:" + ex.Message.Replace("'", "\\'") + ",请重新导入');</script>");
    }
    finally
    {
        // 确保数据库连接关闭,避免连接泄漏
        if (conn != null && conn.State == ConnectionState.Open)
        {
            conn.Close();
        }
    }
}

对应的BLL层Add方法修改示例:

public void Add(YourModel model, SqlTransaction tran)
{
    // 假设你的DAL层基于SqlCommand实现,这里替换成你的实际表名和字段
    string sql = "INSERT INTO YourTableName (orgid, orgname, Unumber, percode, pername, perdate, pernum, addname, addtime) VALUES (@orgid, @orgname, @Unumber, @percode, @pername, @perdate, @pernum, @addname, @addtime)";
    
    using (SqlCommand cmd = new SqlCommand(sql, tran.Connection, tran))
    {
        cmd.Parameters.AddWithValue("@orgid", model.orgid);
        cmd.Parameters.AddWithValue("@orgname", model.orgname);
        cmd.Parameters.AddWithValue("@Unumber", model.Unumber);
        cmd.Parameters.AddWithValue("@percode", model.percode);
        cmd.Parameters.AddWithValue("@pername", model.pername);
        cmd.Parameters.AddWithValue("@perdate", model.perdate);
        cmd.Parameters.AddWithValue("@pernum", model.pernum);
        cmd.Parameters.AddWithValue("@addname", model.addname);
        cmd.Parameters.AddWithValue("@addtime", model.addtime);
        
        cmd.ExecuteNonQuery();
    }
}

关键注意点:

  • 事务范围:必须确保所有插入操作都复用同一个数据库连接和事务,不能让BLL层自行创建新连接(否则事务无法覆盖所有操作)。
  • 连接管理:一定要在finally块中关闭数据库连接,避免出现连接泄漏问题。
  • 异常细节:可以在catch块中添加日志记录,方便后续排查导入失败的具体原因。
  • 原代码修正:你原来的model.orgid = dt.Rows[i]["X1"] + "00".ToString();存在语法问题,我已经在示例中调整为dt.Rows[i]["X1"].ToString() + "00",确保逻辑正确。

内容的提问来源于stack exchange,提问作者user18419939

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 15:02:40