c# - 向sql插入值时从字符串转换为uniqueidentifier时转换失败
问题描述
我有一个名为 test 的简单 SQL 表,它有两列。第一列是 TINYINT,第二列是 UNIQUEIDENTIFIER 类型。
我创建了使用 for 循环将值插入“测试”表的简单方法,并且它工作正常,没有任何错误。但是一旦我尝试创建字符串到唯一标识符转换错误,它将回滚事务并删除同一事务中所有先前插入的值.
这是发生转换的地方
strCommand += "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString()) + "'); ";
这是我的完整代码
private static string TryThisPlease()
{
SqlConnection connection = null;
SqlCommand command = null;
SqlTransaction transaction = null;
string strRet = "OK";
try
{
connection = new SqlConnection(connectionString);
connection.Open();
//starting transaction mode
transaction = connection.BeginTransaction(IsolationLevel.Snapshot);
command = new SqlCommand("Test", connection);
command.CommandType = CommandType.Text;
command.Transaction = transaction;
//for (int i = 255; i < 257; i++)
for (int i = 250; i < 255; i++)
{
string[] strData = new string[] { "", "3" };
string strCommand = "";
//strCommand += "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + Guid.NewGuid().ToString() + "'); ";
strCommand += "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString()) + "'); ";
command.CommandText = strCommand;
if (command.Connection.State != ConnectionState.Open)
command.Connection.Open();
try
{
command.ExecuteNonQuery();
}
catch (Exception EX)
{
strRet = "FAIL";
try
{
}
catch (Exception)
{
strRet = "FAIL";
}
}
}
transaction.Commit();
}
catch (Exception EX)
{
transaction.Rollback();
strRet = "FAIL";
}
finally
{
connection.Close();
}
return strRet;
}
取消注释已注释的两行并注释掉下面的行,会发生另一个具有相同严重性的错误。在这种情况下事务不会回滚
有什么方法可以防止事务回滚还是我错过了代码中的某些内容?
解决方案
如果您希望之前的插入成功,您需要做的是在 foreach 循环内创建并提交事务,以便将每一行视为单独的事务。
using(SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
for (int i = 250; i < 255; i++) {
using(SqlCommand command = new SqlCommand("", connection, trans)) {
command.CommandType = System.Data.CommandType.Text;
using(SqlTransaction trans = connection.BeginTransaction()) {
try {
strCommand = "INSERT INTO Test(Test, Test2) VALUES(" + i.ToString() + ", '" + (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString()) + "'); ";
command.CommandText = strCommand;
command.ExecuteNonQuery();
trans.Commit();
}
catch(Exception e) {
//Handle Error
trans.Rollback();
}
}
}
}
}
但是,您的命令很容易受到 sql 注入攻击。我建议您将查询参数化,如下所示:
SqlCommand cmd = new SqlCommand(
"INSERT INTO Test(Test, Test2) VALUES(@id1,@id2)", conn);
cmd.Parameters.Add( new SqlParameter(@id1, SqlDbType.Int)).Value = i;
cmd.Parameters.Add( new SqlParameter(@id2, SqlDbType.Guid)).Value = (i == 251 ? Guid.NewGuid().ToString().Remove(12, 1) : Guid.NewGuid().ToString());
更新 如果您仍想使用批量事务,您可以考虑事务的保存点。您可以回滚到保存点,而不是回滚整个事务。阅读有关 Savepoint 的更多信息
command.CommandText = strCommand;
trans.Save($"save{i}");
command.ExecuteNonQuery();
trans.Commit();
}
catch(Exception e) {
//Handle Error
trans.Rollback($"save{i}");
trans.Commit();
}
推荐阅读
- r - 当列中的值等于 R 中的 X 时,如何使用 if else 语句而不应用它或跳过它?
- angular - 更新列表时,Angular *ngFor 不响应
- javascript - 如何使用 JavaScript 处理来自 JSON 响应的自定义错误?
- swiftui - 从 SwiftUI 视图推送到 iOS13 中的 Storyboard 项目时,导航视图隐藏
- vba - 长文件路径无法将文件复制到新目录
- tkinter - Tkinter 小部件文本:计算行数
- python - 如何仅从 Python 中的 Dictionary 末尾删除单引号
- r - 使用神经网络更新 R 中的 DQN
- python - 更改列表值并再次运行该函数后,该值将重置为原来的值
- node.js - 在退出之前,异步 lamdba 是否会运行事件循环中的每个事件(没有等待)