非TransactionScope事务隔离级别指定及类型转换报错解惑
问题解析与修复方案
这个问题我之前帮不少开发者排查过,核心是命名空间的枚举混淆,再加上代码里有两个关键的遗漏点,咱们一步步来解决:
一、先解决隔离级别类型转换错误
你遇到的无法将‘System.Transactions.IsolationLevel’转换为‘System.Data.IsolationLevel’错误,本质是枚举的命名空间冲突:
SqlConnection.BeginTransaction()方法要求传入的是System.Data命名空间下的IsolationLevel枚举;- 如果你的代码顶部同时引用了
using System.Transactions;和using System.Data;,编译器会搞不清你用的是哪个枚举,就会抛出这个转换错误。
修复方式二选一:
- 方式1:明确指定命名空间
把事务开启的代码改成:transaction = connection.BeginTransaction(System.Data.IsolationLevel.RepeatableRead); - 方式2:优化命名空间引用
去掉不需要的using System.Transactions;(如果你没用到TransactionScope的话),或者给枚举取别名:using DataIsolation = System.Data.IsolationLevel; // 然后开启事务时用: transaction = connection.BeginTransaction(DataIsolation.RepeatableRead);
二、你的代码存在两个关键遗漏点
1. SqlCommand未关联到事务
你创建了SqlTransaction对象,但没有把它绑定到SqlCommand的Transaction属性上!这会导致你的INSERT操作根本不在事务范围内执行——哪怕后面执行Rollback(),这条INSERT已经被提交到数据库了,完全失去了事务的原子性。
必须加上这行代码:
cmd.Transaction = transaction;
2. 缺失异常处理逻辑
如果在ExecuteScalar()或者CreateSalesLinesWithForLoop()过程中抛出异常(比如数据库连接中断、约束冲突),你的代码会直接跳出using块,根本不会执行Rollback(),这会导致事务处于悬挂状态,占用数据库资源。
需要用try-catch块包裹事务操作,确保异常时能回滚。
修正后的完整代码
public bool CreateSale(Sale sale) { int count = 0; bool isSuccessful = false; using (SqlConnection connection = DBConnection.OpenConnection()) { connection.Open(); // 注意:如果OpenConnection()没打开连接,这里要手动Open SqlTransaction transaction = null; using (SqlCommand cmd = connection.CreateCommand()) { try { // 明确指定System.Data下的隔离级别 transaction = connection.BeginTransaction(System.Data.IsolationLevel.RepeatableRead); // 把命令关联到事务 cmd.Transaction = transaction; cmd.CommandText = $"INSERT INTO Sale(total_price, customer_id) OUTPUT INSERTED.id VALUES (@p1, @p2);"; cmd.Parameters.AddWithValue("@p1", sale.TotalPrice); cmd.Parameters.AddWithValue("@p2", sale.Customer.Id); sale.Id = (int)cmd.ExecuteScalar(); count = _salesLineDB.CreateSalesLinesWithForLoop(sale, connection); if (count == sale.SalesLines.Count) { transaction.Commit(); isSuccessful = true; } else { transaction.Rollback(); } } catch (Exception ex) { // 异常时务必回滚事务 transaction?.Rollback(); // 可以在这里记录日志或者重新抛出异常 throw; } } } return isSuccessful; }
另外补充一点:如果你的DBConnection.OpenConnection()方法返回的是未打开的连接,记得要手动调用connection.Open(),否则BeginTransaction()会抛出异常。
内容的提问来源于stack exchange,提问作者user9476827
相关产品推荐
相关产品推荐

