ASP.NET C# Excel导入SQL Server异常后的数据回滚解决方案咨询
解决Excel导入SQL Server时异常数据回滚的问题
你的问题核心是缺少数据库事务控制——当前代码每执行一次bll.Add(model)就会独立提交一次数据到数据库,一旦中间抛出异常,已经执行的插入操作无法撤销。要实现异常时回滚到导入前的状态,我们需要用数据库事务把所有插入操作包裹起来,确保要么全部成功提交,要么全部失败回滚。
具体实现步骤:
- 开启数据库事务:在读取Excel数据之后、开始循环插入之前,创建数据库连接并开启事务。
- 让BLL层支持事务:修改你的
bll.Add方法,允许传入SqlTransaction参数,确保所有插入操作都在同一个事务中执行。 - 事务的提交与回滚:如果所有插入都成功,提交事务;如果中途抛出异常,立即回滚事务,撤销所有已执行的插入操作。
修改后的完整代码示例:
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
相关产品推荐
相关产品推荐

