2

我有一个 Windows 窗体应用程序,只需单击一个按钮即可在数据库中执行一些 sql 脚本。这些 sql 脚本执行用户创建,并提供一些权限,如数据执行、数据读/写等。这是我的示例 c# 代码这样做:

script1 = "CREATE USER " + username + " FROM LOGIN " + username;
script2 = @"CREATE ROLE [db_execute] AUTHORIZATION [dbo]
                        GRANT EXECUTE TO [db_execute]";

script3 = @"DECLARE @rolename varchar(max)
                    SET @rolename ='{0}'
                    EXEC sp_addrolemember N'db_execute',@rolename
                    EXEC sp_addrolemember N'db_datareader', @rolename
                    EXEC sp_addrolemember N'db_datawriter', @rolename";

并在数据库中执行此操作,如:

SqlCmd.CommandText = script1;
SqlCmd.Connection = oConnection;
var ans = SqlCmd.ExecuteNonQuery();

if (!ans.Equals(0))
{
    //some task
} else
{
    //messagebox
}

SqlCmd.CommandText = script2;
SqlCmd.Connection = oConnection;
var answer = SqlCmd.ExecuteNonQuery();

if (!answer.Equals(0))
{
    //some task
} else
{
    //messagebox
}

SqlCmd.CommandText = script3;
SqlCmd.Connection = oConnection;
var answ = SqlCmd.ExecuteNonQuery();

if (!answ.Equals(0))
{
    //some task
} else
{
    //messagebox
}

我通过按一个按钮一次执行所有这些脚本,所以据我所知,我将其作为单个事务执行。我想要做的是,如果这些脚本中的任何一个在两者之间失败,我应该能够完全回滚而不做任何更改。

为了给你一个更好的画面,如果脚本3的执行由于某种原因失败,它应该自动回滚数据库中的脚本1和脚本2。

我们应该怎么做?我用谷歌搜索了一下,发现了一些与此无关的帖子。

任何帮助或想法将不胜感激..

4

5 回答 5

2

使用 SqlConnection 和 SqlTransaction 对象。尝试这个;

   {       
     // declarations

     try
     {
        // open connection
        trans = conn.BeginTransaction();
        cmd.Transaction = trans;   // Includes this cmd as part of the trans

        SqlCmd.CommandText = script1;
        SqlCmd.Connection = oConnection;
        var ans = SqlCmd.ExecuteNonQuery();


        if (!answ.Equals(0))
        {
           //some task
        } else
        {
           //messagebox
        }

       // Your other queries

       trans.Commit(); // commit transaction

     }
     catch (Exception e){
        trans.Rollback();
        throw e;
     }
     finally{
        conn.Close();
   }
于 2013-09-24T12:04:44.283 回答
1

我使用 System.Transactions.TransactionScope,如果您将其封装在 using 语句中,请将代码放入其中,然后使用 scope.complete。

于 2013-09-24T12:04:24.930 回答
1

根据您的数据库系统,只有DML(数据操作,SELECT/INSERT/UPDATE/DELETE)可以是事务性的,因此可以回滚。DDL(数据定义,如 ALTER 或 CREATE)不能成为事务的一部分。事实上,根据DBMS,这些语句将在执行时隐式提交所有先前的 DML 语句。

如果您需要事务(因为您DBMS的不同或您实际上有 CRUD 语句),那么您需要在您的上调用BeginTransactionSqlConnection并使用生成的对象来提交或回滚。

于 2013-09-24T12:03:20.850 回答
0

我建议处理 SQL 中的事务并向用户返回正确的消息。原因是您有两个单独的层数据访问层 (DAL) 和 UI。

您可以在此处阅读有关 DAL 的更多信息

事务具有以下四个标准属性,通常用首字母缩写词 ACID 表示:

原子性:确保工作单元内的所有操作都成功完成;否则,事务将在故障点中止,并且先前的操作将回滚到它们之前的状态。

一致性:确保数据库在成功提交事务时正确更改状态。

隔离:使交易能够独立运行并且彼此透明。

持久性:确保已提交事务的结果或效果在系统故障的情况下持续存在。

在这里阅读更多

于 2013-09-24T12:24:32.153 回答
0

按照此MSDN 参考中的说明使用 SqlTransaction 类

于 2013-09-24T12:06:46.423 回答