Reputation: 2155
When using the ADO.Net driver for MySQL in .NET, is it necessary to assign a transaction to the MySqlCommand
object (for example, using oCmd.Transaction = oTran
) or is it enough that the MySqlConnection
object has an open transaction? In the code below I begin a transaction on the connection, run two queries with separate MySqlCommand
objects without assigning a transaction and then roll back the transaction. In this example, neither UPDATE
is committed to the database.
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();
When checking the Transaction
property of oCmd
at runtime, I see that it is null
.
Obviously, if I call oTran.Commit()
then both UPDATE
statements are committed. So what is the purpose of the Transaction
property of the MySqlCommand
object? Is it to allow more than one concurrent transaction on a single connection (where different commands would be bound to different transactions and could be rolled back or committed irrespective of each other)?
Upvotes: 0
Views: 3515
Reputation: 416059
For a single statement, you can pretend the property doesn't exist, along with the Commit()
and Rollback()
methods. If the property is not there, individual statements are auto-committed. In the code from the question, it would be possible to run a query in the brief span between when testID=1 is updated and testID=2 is updated, and the Rollback()
method won't accomplish anything.
To take advantage of the MySqlTransaction object, you need to do this:
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();
}
Or even better:
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();
}
You need transactions mainly when you want to guarantee multiple operations are atomic. This works when you assign the transaction to each instance of the command object individually, each instance of the command uses the same connection, and the connection is held open for the duration of the transaction.
Additionally, you can put multiple statements into a single command object:
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();
}
This is the preferred method, but sometimes the nature of your code will prevent it, and you'll have to use the MySqlTransaction
object instead.
Upvotes: 1