We use application in server with Sql server and it receive many SDF file from clients to update the SqlServer Data Base the update for many Tables and I use Transaction for this, the application in server used by multiple user than it possible to be two updates in the same time, and the two with transaction, the application throw an exception that table used by another transaction !!
New transaction is not allowed because there are other threads running in the session.
and the user have other task to do in the app with transaction too, for the moment if there's an update he have to wait until it finish.
Any ideas?
Update : there's some code for my fonction : this is my fonctions with transaction run in BackgroundWorker with timer :
DbTransaction trans = ConnectionClass.Instance.MasterConnection.BeginTransaction();
try
{
ClientDalc.UpdateClient(ChosenClient, trans);
// other functions with the same transaction
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
return false;
}
Update Client:
public static bool UpdateClient(ClientEntity ChosenClient, DbTransaction trans)
{
bool retVal = true;
string sql = "UPDATE ClientTable Set ........";
try
{
using (DbCommand cmd = DatabaseClass.GetDbCommand(sql))
{
cmd.Transaction = trans;
cmd.Parameters.Add(DatabaseClass.GetParameter("#Name", Client.Name));
//
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
retVal = false;
}
return retVal;
}
If I run any thing else in the same time that BackgroundWorker is in progress I got exception even is not a transaction
ExecuteReader requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.”
Is this a totally borked posting?
The only reference I find to that error points to Entity Framework, NOT Sql server and I ahve never seen that in sql server - in fact, sql server has no appropiate conceot for session at all. They are called Conenctions there.
SqlException from Entity Framework - New transaction is not allowed because there are other threads running in the session
In that case your description and the tagging makes ZERO sense and the onyl answer is to use EntityFramework PROPERLY - i.e. not multi threaded. Open separate sessions per thread.
Try to follow the sample C# code
using (SqlConnection con = new SqlConnection("Your Connection String"))
{
using (SqlCommand cmd = new SqlCommand("Your Stored Procedure Name", con))
{
SqlParameter param = new SqlParameter();
param.ParameterName = "Parameter Name";
param.Value = "Value";
param.SqlDbType = SqlDbType.VarChar;
param.Direction = ParameterDirection.Input;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
}
Try to follow sample Stored Procedure
Create Proc YourStoredProcedureName
#ParameterName DataType(Length)
As
Begin
Set NoCount On
Set XACT_ABORT ON
Begin Try
Begin Tran
//Your SQL Code...
Commit Tran
End Try
Begin Catch
Rollback Tran
End Catch
End
Suggestions
Keep your transaction as short as possible.
When you are adding a record in table, it will definitely lock the resource until the transaction is completed. So definitely other users will have to wait.
In case of updation, you can use concurrency controls
Related
I write stored procedures with read uncommitted transaction isolation level, but when connection time out the rollback in catch in SQL doesn't work.
When I use SqlTransaction in my business layer in .Net, the problem is solved
and I can support any errors occurred in SQL in my try... catch in .Net.
Is this what I did right?
using (SqlConnection conn = new SqlConnection(Data.DataProvider.Instance().ConnectionString))
{
conn.Open();
SqlTransaction tran = conn.BeginTransaction(IsolationLevel.ReadUncommitted, "Trans");
try
{
object ores = SqlHelper.ExecuteScalar(.......)
string res = ores.ToString();
if (string.IsNullOrEmpty(res))
{
tran.Rollback();
info.TrackingCode = "";
return 0;
}
else if (res == "-4")
{
tran.Rollback();
return -4;
}
else if (res == "-1")
{
tran.Rollback();
return -1;
}
else
{
tran.Commit();
return 1;
}
}
catch (Exception)
{
tran.Rollback();
info.TrackingCode = "";
return 0;
}
As per your requirement, there can be two ways to define SqlTransactions
SQL Server side SqlTransaction
C#.NET (business layer) SqlTransaction.
(Both can not be mixed)
In your case, you tried to define SqlTransaction at the business layer. So better you call Stored-procedure too in the business layer. So the Business layer will rectify the SqlTransaction and time-Out error won't occur.
So first include your Stored-Procedure code as a Command execution (at business layer) and then execute.
Change your code as below with your required conditions.
// Command Objects for the transaction
SqlCommand cmd1 = new SqlCommand("YourStoredProcedureName", cnn);
cmd1.CommandType = CommandType.StoredProcedure;
//If you are using parameter for the Stored-procedure
cmd1.Parameters.Add(new SqlParameter("#Param1", SqlDbType.NVarChar, 50));
cmd1.Parameters["#Param1"].Value = paramValue1;
//Execute stored procedure through C# code
cmd1.ExecuteNonQuery();
transaction.Commit();
EDITED: Reference link
catch (SqlException sqlEx)
{
if (sqlEx.Number == -2)
{
//handle timeout
}
transaction.Rollback();
}
When a client timeout event occurs (.net CommandTimeout for example), the client sends an "ABORT" to SQL Server. SQL Server then simply abandons the query processing. No transaction is rolled back, no locks are released. I solved this problem with Sqltransaction in my .Net Code Instead Sql and Mange Exceptions with SqlExceptions
Both ways are equivalent. But in the case of the business layer, you can handle the transaction through multiple query executions.
Here, you should handle conn.Open() for possible exceptions. Also, check SqlHelper uses your created connection and transaction everywhere in its code.
I've 2 queries that must work together. First is an Update and second is an Insert query. I placed them into TransactionScope scope:
using (TransactionScope scope = new TransactionScope())
{
SqlCommand updateCmd = new SqlCommand("UPDATE V_Stock SET Quantity= 5 WHERE Id=" + shelfId, con);
SqlCommand insertCmd = new SqlCommand("INSERT INTO V_Stock (Code, Quantity, Name) VALUES (#1, #2, #3)", con);
insertCmd.Parameters.AddWithValue("#1", "Code1");
insertCmd.Parameters.AddWithValue("#2", 15);
insertCmd.Parameters.AddWithValue("#3", "Name1");
try
{
updateCmd.ExecuteNonQuery();
insertCmd.ExecuteNonQuery();
}
catch (Exception ex)
{
scope.Complete();
string s = ex.ToString();
}
}
The update query works properly however the insert query doesn't. In this case, I don't want to execute them. They should be executed when only they work properly.
What can I do to work these queries together?
You need to call scope.Complete when you are ready to commit your transaction, not when it fails.
You should also open the connections inside the scope of the TransactionScope so the connection is registered with that scope.
Also I am not sure where your SqlConnection instance is defined. The Microsoft team always recommends you use short lived connections, use them and get rid of them. Let Sql Server handle connection pooling (usually this is on by default) which makes it very cheap to use and throw away sql connections inside your c# code.
Here is some refactored code and I added some documentation that I found on the Microsoft definition for TransactionScope
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection con = new SqlConnection(yourConnectString))
{
// according to the documentation on TransactionScope
// Opening the connection automatically enlists it in the
// TransactionScope as a lightweight transaction.
con.Open();
// I changed this to make it parameterized as well although this had nothing to do with the TransactionScope question
SqlCommand updateCmd = new SqlCommand("UPDATE V_Stock SET Quantity= 5 WHERE Id= #shelfId", con);
updateCmd.Parameters.AddWithValue("#shelfId", shelfId);
SqlCommand insertCmd = new SqlCommand("INSERT INTO V_Stock (Code, Quantity, Name) VALUES (#1, #2, #3)", con);
insertCmd.Parameters.AddWithValue("#1", "Code1");
insertCmd.Parameters.AddWithValue("#2", 15);
insertCmd.Parameters.AddWithValue("#3", "Name1");
updateCmd.ExecuteNonQuery();
insertCmd.ExecuteNonQuery();
// according to the documentation on TransactionScope
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
}
Question:
Is there a way to stop the Command.ExecuteNonQuery() before it is completed, without using timeout?
I have created a multi-threaded MySQL program that stores and run sql statements. Allowing a group of transactions run at the same time (because they do not modify the same tables).
I have had to Disable the Timeout(set it to 0), because some SQL Statements can take several mins to run.
The problem comes when I want to stop the queries. Right now I have to wait till that current SQL Statement finished (like I said it could take several mins).
Below is code that works, from my existing knowledge (To help others):
MySqlConnectionStringBuilder ConnectionString = new MySqlConnectionStringBuilder();
ConnectionString.Server = ServerName; // ServerName is a user defined string
ConnectionString.Database = DatabaseName; // DatabaseName is a user defined string
ConnectionString.UserID = UserName; // UserName is a user defined string
if (!Password.Equals(string.Empty)) // Password is a user defined string
{ ConnectionString.Password = Password; } // If Password string is not empty, then add it.
ConnectionString.AllowUserVariables = true;
using (MySqlConnection connection = MySqlConnection(ConnectionString))
{
try
{
connection.Open();
DBTransaction Trans = connection.BeginTransaction();
using (MySqlCommand Command = connection.CreateCommand())
{
foreach(String SQLCommandString in SQLCommands) // SQLCommands is user defined List<String>
{
try
{
Command.CommandText = SQLCommandString; // SQLCommandString is a user defined string ex "UPDATE MyTable SET MyVar = 3 WHERE id = 3;"
NumOfRecordAffected = Command.ExecuteNonQuery();
}
catch (MySql.Data.MySqlClient.MySqlException ex)
{
Trans.RollBack();
// If code reaches here then there was a problem with the SQLCommandString executing.
throw ex;
}
catch (Exception ex)
{
// There was a problem other than with the SQLCommandString.
throw ex;
}
}
}
Trans.Commit();
}
You can't do this in a single threaded application, because control won't return until a) the query has completed execution or b) an exception forces control to return.
Instead, you can start and execute all transactions in a worker thread and close the connection from the original thread if needed. Calling MySqlConnection.Close() will rollback any pending transactions.
I am using stored procedures in sql server.
I have several stored procedures calls written in c#. I want to wrap them inside transaction:
//Begin Transaction here
sp1Call();
sp2Call();
sp3Call();
//Commit here
//Rollback if failed
is there any way to do it?
Update:
I am using the enterprise library. example to sp1Call():
public static void sp1Call(string itemName)
{
DbCommand command = db.GetStoredProcCommand("dbo.sp1_insertItem");
db.AddInParameter(command, "#item_name", DbType.String, itemName);
db.ExecuteNonQuery(command);
}
You'll want to check out SqlTransaction.
Just a quick search comes up with DBTransaction:
using (DbConnection connection = db.CreateConnection())
{
connection.Open();
DbTransaction transaction = connection.BeginTransaction();
try
{
DbCommand command = db.GetStoredProcCommand("dbo.sp1_insertItem");
db.AddInParameter(command, "#item_name", DbType.String, itemName);
db.ExecuteNonQuery(command, transaction);
transaction.Commit();
}
catch
{
//Roll back the transaction.
transaction.Rollback();
}
}
I am a C# programmer. I want to clear this complex concept.
If there are 2 databases: A and B. Suppose I want to insert records in both but first in A and then in B. Say if while inserting in db B an exception occurs. The situation is that if B crashes, transaction with db A should also be rolled back. What do I have to do?
I know I can use SqlTransaction object with SqlConnectionString class. Can I have some code for this?
Already asked here : Implementing transactions over multiple databases.
Best answer from keithwarren7 :
use the TransactionScope class like this
using(TransactionScope ts = new TransactionScope())
{
//all db code here
// if error occurs jump out of the using block and it will dispose and rollback
ts.Complete();
}
The class will automatically convert to a distributed transaction if necessary.
.
Edit : adding explanations to original answer
You've got a good example in the MSDN : http://msdn.microsoft.com/fr-fr/library/system.transactions.transactionscope%28v=vs.80%29.aspx.
This example shows you how to use 2 Database Connections in one TransactionScope.
// Create the TransactionScope to execute the commands, guaranteeing
// that both commands can commit or roll back as a single unit of work.
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection connection1 = new SqlConnection(connectString1))
{
try
{
// Opening the connection automatically enlists it in the
// TransactionScope as a lightweight transaction.
connection1.Open();
// Create the SqlCommand object and execute the first command.
SqlCommand command1 = new SqlCommand(commandText1, connection1);
returnValue = command1.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command1: {0}", returnValue);
// If you get here, this means that command1 succeeded. By nesting
// the using block for connection2 inside that of connection1, you
// conserve server and network resources as connection2 is opened
// only when there is a chance that the transaction can commit.
using (SqlConnection connection2 = new SqlConnection(connectString2))
try
{
// The transaction is escalated to a full distributed
// transaction when connection2 is opened.
connection2.Open();
// Execute the second command in the second database.
returnValue = 0;
SqlCommand command2 = new SqlCommand(commandText2, connection2);
returnValue = command2.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
}
catch (Exception ex)
{
// Display information that command2 failed.
writer.WriteLine("returnValue for command2: {0}", returnValue);
writer.WriteLine("Exception Message2: {0}", ex.Message);
}
}
catch (Exception ex)
{
// Display information that command1 failed.
writer.WriteLine("returnValue for command1: {0}", returnValue);
writer.WriteLine("Exception Message1: {0}", ex.Message);
}
}
// The Complete method commits the transaction. If an exception has been thrown,
// Complete is not called and the transaction is rolled back.
scope.Complete();
}
If you like to have only one connection and like to manage the things then you may using the Linked Server and call the SP from server A which can call the SP from Server B
:)