C#查询股东余额后循环更新时出现连接未关闭错误求助
问题分析与修复
错误根源
你的代码中,SqlDataReader在读取数据时会独占数据库连接,此时在同一个连接上执行ExecuteNonQuery(更新操作)会触发连接冲突,导致“连接未关闭”类错误。因为DataReader打开期间,连接被锁定用于读取,无法同时执行其他命令。
另外原代码还有两个潜在问题:
- 未使用
using语句管理连接、命令和DataReader,一旦出现异常,连接可能无法正常关闭,导致连接泄漏。 - 判断
rdr["current_balance"] != null无效,数据库中的NULL值在DataReader中会以DBNull.Value形式存在,应该用rdr.IsDBNull()判断。
最优修复方案:单条SQL直接更新
不需要逐行读取数据再更新,直接用SQL语句在数据库层面完成计算和更新,性能更高且完全避免连接冲突:
try { // 使用using自动释放连接,无需手动Close using (var con = new SqlConnection(constr)) { con.Open(); // 直接通过SQL计算新余额,同时更新两个字段 string updateSql = @"UPDATE shareholders_term SET profit_percentage = @profitPercentage, current_balance = current_balance * (1 + @profitPercentage / 100) WHERE current_balance IS NOT NULL"; var cmd = new SqlCommand(updateSql, con); cmd.Parameters.AddWithValue("@profitPercentage", profitpercentage); int updatedCount = cmd.ExecuteNonQuery(); lblupdatecounter.Text = updatedCount + " - Shareholders updated."; MessageBox.Show("Profit added to shareholders"); } } catch (Exception ex) { MessageBox.Show(ex.Message); }
若需保留逐行处理逻辑(如额外业务)
如果必须逐行处理(比如有其他业务逻辑要执行),可以先把数据读到内存,再关闭DataReader后进行更新:
try { // 1. 先读取所有需要更新的数据到内存 var shareholderList = new List<(int ShareholderId, decimal CurrentBalance)>(); using (var con = new SqlConnection(constr)) { con.Open(); string selectSql = "SELECT shareholder_id, current_balance FROM shareholders_term WHERE current_balance IS NOT NULL"; using (var cmd = new SqlCommand(selectSql, con)) using (var rdr = cmd.ExecuteReader()) { while (rdr.Read()) { int id = Convert.ToInt32(rdr["shareholder_id"]); decimal balance = Convert.ToDecimal(rdr["current_balance"]); shareholderList.Add((id, balance)); } } // DataReader自动关闭 } // 连接自动关闭 // 2. 逐行更新数据 int num = 0; using (var con = new SqlConnection(constr)) { con.Open(); string updateSql = @"UPDATE shareholders_term SET profit_percentage = @percentage, current_balance = @newBalance WHERE shareholder_id = @shareholderId"; foreach (var shareholder in shareholderList) { num++; decimal profitAmount = shareholder.CurrentBalance * profitpercentage / 100; decimal newBalance = shareholder.CurrentBalance + profitAmount; using (var cmd = new SqlCommand(updateSql, con)) { cmd.Parameters.AddWithValue("@percentage", profitpercentage); cmd.Parameters.AddWithValue("@newBalance", newBalance); cmd.Parameters.AddWithValue("@shareholderId", shareholder.ShareholderId); cmd.ExecuteNonQuery(); } lblupdatecounter.Text = num + " - Shareholders updated."; } } MessageBox.Show("Profit added to shareholders"); } catch (Exception ex) { MessageBox.Show(ex.Message); }
内容的提问来源于stack exchange,提问作者user3387814
相关产品推荐
相关产品推荐

