I have a MySQL table implementing a mail queue, and I use it also to send mails which reports unexpected errors in the system. Sometimes these unexcepted errors ocurrs inside a transaction so when I rollback the transacion also I undo the row inserted (the mail which is reporting the unexpected error) in the mail queue table.
My question is how can I force to insert a row in a table in the middle a transaction ignoring the possible transaction rollback?. I mean, If the transactions finally rollsback, not to rollback also the row insertion for the email reporting the error details.
This table can be read by multiple asyncronous process to send the mails in the queue, so in this scenario the rows have to be blocked to send only once the emails so is not possible to use a MyISAM table type and is using Innodb.
Thanks in advance.
If you INSERT should survive a ROLLBACK of the transaction, it is safe to say, that it is not part of the transaction. So what you should do is to simply move it outside the transaction. There are many ways to achieve that:
While in the transaction, instead of running you INSERT, store the
fields in session variables (these will survive a ROLLBACK), after
the transaction run the insert from the session variables
Rethink your schema - this reeks of some deeper-lying problem
Open a second DB connection and run your INSERT on this one, it will not be affected by the transaction on the first connection.
You could create a different connection to the database to insert the errors and it won't be in the same transaction context, so they would be inserted.
Related
I am new to c# and sql server. I'am using SQL Server 2008 and I have 126 tables in my database.
There are 7 transaction tables on which insert/update query fires frequently as there are 30-40 users for my application.
I have written BEGIN TRAN before every query and COMMIT at the end of the query.
Now many-a-times I get error 'Timeout expired ...' when any random user tries to open a form or save some data.
I have written ROLLBACK in my triggers if the trigger throws an error.
But I could not identify on which table BEGIN TRAN has happened or which table is deadlocked.
I have made sure that my connection is proper and is open, then I'am getting this error too
and I couldn't identify from where it is comming.
Does anyone have any idea from where this 'Timeout expired' error is comming and can suggest me some way out?
Does any one have any idea from where this 'Timeout expired' error is coming and can suggest me some way out.
One of the possible reasons is that the transaction cannot acquire lock on some resource(table, row, ...).
In that case you may try to increase the LOCK_TIMEOUT or change the isolation level(if acceptable).
I would suggest reading this article.
We want to obtain an auto-increment ID from mySQL without actually storing it until the other non-mysql related processes are successfully completed, so that the entry is not stored if an exception or application crash happens. We need to use the ID as a key for the other processes. In essence we want to “reserve” the auto-increment and insert the rows into mySQL as the last step. We don’t want to insert any row until we know the entire process has completed successfully.
Is it possible to do this sort of auto-increment reservation in mySQL?
Note: I know about the SQL transactions. But our process contains non-SQL stuff that need to happen outside of the DB. These process may take few mins to several hours. But we don't want any other process using the same auto-increment ID. That is why we want a "reserve" an auto-increment ID without really inserting any data into the DB. –
The only way to generate an auto-increment value is to attempt the insert. But you can roll back that transaction, and still read the id generated. In MySQL 5.1 and later, the default behavior is that auto-increment values aren't "returned" to the stack when you roll back.
START TRANSACTION;
INSERT INTO mytable () VALUES ();
ROLLBACK;
SELECT LAST_INSERT_ID() INTO #my_ai_value;
Now you can be sure that no other transaction will try to use that value, so you can use it in your external processes, and then finally insert a value manually that uses that id value (when you insert a specific id value, MySQL does not generate a new value).
Have you considred using mysql tranactions?
The essense of it, you start a transaction, if all sql statements are correct and can be complteted, then you commit your transaction. If not, then you rollback as if nothing happened.
More details can be read in this link:
http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html
you can use temporary table along with transaction
if transaction complete temp table will be gone and move data to real table
http://www.tutorialspoint.com/mysql/mysql-temporary-tables.htm
I am using Django and MySQL. I need to be able to do what in Oracle is called an autonomous transaction, that is, committing only part of a transaction (or, rather, having a transaction within a transaction). I need this for two cases (although I'm thinking that the solution will be the same):
Error logging. I log errors in an error table and want to commit these inserts even if I rollback all other transactions.
I use a table to create a sequence (using TABLE sequence and LAST_INSERT_ID() as described here: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html). I want to get/update this sequence and then commit the statement, thereby unlocking the table for other transactions that need the sequence. It's fine if the table gets incremented even if I rollback the other transactions.
Interesting subject, apparently there's no such thing in mysql but a guy recommends to use (for your log table problem) a myisam table, so since it is outside transactions, the data gets posted anyway.
I am adding a second answer since I just figured out this alternative: what you could do is to handle the log transaction from another connection with another user in your database.
Mysql handles the connection pool per user so it will never use the same connection for the main operations and the log operations, allowing you to commit the logs connection independently.
I'm using MySQL + PHP. I have some code that generates payments from an automatic payment table based on when they are due (so you can plan future payments... etc). The automatic script is run after activity on the site and sometimes gets run twice at the same time. To avoid this, we generate a uuid for a payment where there only can be on nth payment for a specific automatic payment. We also use transactions to encapsulate the whole payment generation process.
As part of this, we need the whole transaction to fail if there is a duplicate uuid, but getting an actual database error will show an error to the user. Can I use Insert Ignore in the payment insert SQL? Will the warning kill the transaction? If not, how can I kill the transaction when there is a duplicate uuid?
To clarify: if the INSERT fails, how can I get it to not throw a program-stopping error, but kill/rollback the transaction?
Mind you, the insert will fail on commit, not on initial execution in the php.
Thanks much!
Maybe there is another approach - making sure the same UUID isn't read twice, instead of relying on a query failure.
I am guessing you get the UUID from another table before you process it and insert.
You can use a transaction and then SELECT ... FOR UPDATE when you read the records. This way the records you read are locked. When you get all the data update a status column to "processed" and COMMIT the transaction.
Finally, make sure the process doesn't read records with status "processed".
Hope this helps...
Just stumbled upon this. And it is an old question but I would try to give an answer.
First: Make sure your payment job only runs one at a time. Guess that could save you a lot of trouble.
Second: If your update statement fails in php, put it in a try-catch Block. That way your mysql query fails but will the error will not be shown to the user and you can handle it.
try {
... your mysql code here ....
} catch (Exception $e) {
... do whatever needs to be done in case of problem ...
}
Keep in mind that there are a lot of possible source for an exception. Never take a failing insert as the reason for granted.
Is there any way to set MySQL to rollback any transaction on first error/warning automatically?
Now if everything goes well, it commits, but on failure it leaves transaction open and on another start of transaction it commits incomplete changes from failed transaction. So i need to rollback automatically those failed transactions..
(I'm executing queries from php, but i don't want to check in php for failure, as it would make more calls between mysql server and webserver.)
Thank you
I don't know of such feature, but I also don't see how checking for failure would mean more calls:
try:
<my code>
except:
transaction.rollback()
raise
else:
transaction.commit()
-- it's in Python/Django, but it should directly transpose to PHP - and it takes exactly the same amount of code to start new transaction, no matter if there is a problem (exception) or not.
Sorry, You are going to need to do this on your own.
I am not a PHP person, but in SQL: If you create a transaction and do several MySQL operations within the transaction, if you rollback the transaction everything will be rolled back. NOTE: You need to be using a transactional storage engine and autocommit must be set to off.
If all you are concerned about is the transaction coordination traffic then you could create a stored procedure and simply call it.
The reason the database does not automatically commit or rollback is because it does not know what you are trying to do, committing some data and rolling back other data might be acceptable in an app.
the key point to to set autocommit to false.
<?php
$database= new mysqli("sever", "user", "key", "database");
$database->autocommit(FALSE);
$error=0;
//asumming we want to delete a users infomation from two table
$database->query("delete from `pay` where `user`=1 ")?NULL:$error=1;
$database->query("delete from `users` where `id`=1 ")?NULL:$error=1;
if($error=0){
$database->commit();
} else {
$database->rollback();
}
$database->close();
?>