.NET MySqlCommand.Transaction - 它的目的是什么?

时间:2017-06-14 09:52:12

标签: c# mysql transactions ado.net

在.NET中使用MySQL的ADO.Net驱动程序时,是否有必要为MySqlCommand对象分配事务(例如,使用oCmd.Transaction = oTran)或者是否足够MySqlConnection 1}}对象有一个打开的事务?在下面的代码中,我在连接上开始一个事务,使用单独的MySqlCommand对象运行两个查询而不分配事务,然后回滚事务。在此示例中,UPDATE都未提交到数据库。

MySqlConnection oConn = new MySqlConnection("Server=spet-il-cent-02;Port=3306;Database=test;Uid=test;Pwd=test123;CharSet=utf8;");
oConn.Open();
MySqlTransaction oTran = oConn.BeginTransaction();
MySqlCommand oCmd = oConn.CreateCommand();

oCmd.CommandText = "UPDATE testing SET testBalance = testBalance + 10 WHERE testID = 1";
oCmd.ExecuteNonQuery();

oCmd = oConn.CreateCommand();
oCmd.CommandText = "UPDATE testing SET testBalance = testBalance - 10 WHERE testID = 2";
oCmd.ExecuteNonQuery();

oTran.Rollback();

oConn.Close();

在运行时检查Transaction的{​​{1}}属性时,我发现它是oCmd

显然,如果我调用null,则会提交两个oTran.Commit()语句。那么UPDATE对象的Transaction属性的目的是什么?它是否允许在单个连接上允许多个并发事务(不同的命令将绑定到不同的事务并且可以回滚或提交而不管彼此)?

1 个答案:

答案 0 :(得分:0)

对于单个语句,您可以假装该属性不存在,以及Commit()Rollback()方法。如果该属性不存在,则会自动提交单个语句。在问题的代码中,可以在更新testID = 1和更新testID = 2之间的短暂范围内运行查询,并且Rollback()方法将无法完成任何操作。

要利用MySqlTransaction对象,您需要执行以下操作:

using (var Conn = new MySqlConnection("Server=spet-il-cent-02;Port=3306;Database=test;Uid=test;Pwd=test123;CharSet=utf8;"))
{
    Conn.Open();
    MySqlTransation Tran = Conn.BeginTransaction();

    using (var Cmd = new MySqlCommand("UPDATE testing SET testBalance = testBalance + 10 WHERE testID = 1", Conn))
    {
        Cmd.Transaction = Tran;
        Cmd.ExecuteNonQuery();
    }
    using (var Cmd = new MySqlCommand("UPDATE testing SET testBalance = testBalance + 10 WHERE testID = 2", Conn))
    {
        Cmd.Transaction = Tran;
        Cmd.ExecuteNonQuery();
    }
    Tran.Rollback();
}

甚至更好:

using (var Conn = new MySqlConnection("Server=spet-il-cent-02;Port=3306;Database=test;Uid=test;Pwd=test123;CharSet=utf8;"))
using (var Cmd = new MySqlCommand("UPDATE testing SET testBalance = testBalance + 10 WHERE testID = @testID", Conn))
{
    Conn.Open();
    Cmd.Transaction = Conn.BeginTransaction();

    Cmd.Parameteres.Add("@testID", MySqlDbType.Int32).Value = 1;
    Cmd.ExecuteNonQuery();
    Cmd.Parameters["testID"].Value = 2; //I can't remember at the moment if you need the "@" here or not
    Cmd.ExecuteNonQuery();

    Cmd.Transaction.Rollback();
}

当您想要保证多个操作是原子操作时,您需要事务。当您将事务分别分配给命令对象的每个实例,命令的每个实例使用相同的连接,并且连接在事务持续期间保持打开时,此方法有效。

此外,您可以将多个语句放入一个命令对象中:

string sql = 
  "BEGIN;" + 
  "UPDATE testing SET testBalance = testBalance + 10 WHERE testID = 1;" +
  "UPDATE testing SET testBalance = testBalance - 10 WHERE testID = 2;" +
  "COMMIT;";

using (var Conn = new MySqlConnection("Server=spet-il-cent-02;Port=3306;Database=test;Uid=test;Pwd=test123;CharSet=utf8;"))
using (var Cmd = new MySqlCommand(sql, Conn))
{
    Conn.Open();
    Cmd.ExecuteNonQuery();
}

这是首选方法,但有时代码的性质会阻止它,您必须使用MySqlTransaction对象。