MySQL: automatic rollback on transaction failure - mysql

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();
?>

Related

How to handle sql.ErrTxDone

I am for example trying to create a new record in my mysql database. In the case of a sql.ErrTxDone, what does it actually mean, what should i do in-case the transaction was committed ?
You get this error if a transaction is in a state where it cannot be used anymore.
sql.Tx:
After a call to Commit or Rollback, all operations on the transaction fail with ErrTxDone.
And also sql.ErrTxDone:
ErrTxDone is returned by any operation that is performed on a transaction that has already been committed or rolled back.
var ErrTxDone = errors.New("sql: transaction has already been committed or rolled back")
What should you do? Don't use the transaction anymore. If you have further task, do it outside of it or in another transaction.
If you have tasks that should be in the same transaction, don't commit it until you do everything you have to. If the transaction was rolled back (e.g. due to a previous error), you have no choice but to retry (using another transaction) or report failure.
If you're already using transactions, try to put everything in the transaction that needs to happen all-or-nothing. That's the point of transactions. Either everything in it gets applied, or none of them. Using them properly you don't have to think about cleaning up after them. They either succeed and you're happy, or they don't and you either retry or report error, but you don't have to do any cleanup.

Ensure MySQL transaction fails on COMMIT

I want to test a script what it does when MySQL transaction fails. So I want to simulate transaction failure on COMMIT.
Image the script opens a transaction, makes some queries, and then commits the transaction. I want to implant some extra query to the transaction, to ensure the transaction will fail on COMMIT. So I can test how the script recovers from the transation failure.
I don't want to use explicit ROLLBACK. I want to simulate some real-life case when a commit fails. The exact DB structure is unimportant. It may adapt to the solution.
Edit: I need the transaction to fail on COMMIT, not on some prior query. Therefore answers that rollback prior to COMMIT are not what I want. Such as this one: How to simulate a transaction failure?
My unsuccessful attempts:
Inserting a row with invalid PK or FK fails immediately with insert. Temporarily disabling FK checks with FOREIGN_KEY_CHECKS=0 won't help as they won't be rechecked on COMMIT. If it was psql, defferable constraints would help. But not in mysql.
Opening two parallel transactions and inserting a row with the same PK (or any column with unique constaint) in both transactions locks the later transaction on insert and waits for the former transaction. So the transaction rolls back on insert not on commit.
So I believe you can try the following
Two phase commit : Use two database ( First and second) and make
use of two phase commit. When the commit statement is supposed to be
executed you can shutdown the second db. This way your commit
operation will fail and transaction will rollback.
You executed several inserts and before your commit your database server dies. A transaction may fail if it doesn't receive commit .
Hopefully it helps!

Do I need commit if i do only selects in aiomysql

I am using aiomysql (https://github.com/aio-libs/aiomysql) and have some problems with the unclosed transaction and locking rows. I use AIO connections pool in my application.
I am NOT using SA context managers for transactions.
My questions:
If I do only and only SELECT's as I understand there are no locks on rows, So do I need to call wait for conn.commit() or I can skip it if I can skip how MySQL should now what the transaction ends?
In the code below, then AIO MySQL start a new transaction? then acquire() connection called or then create cursor called or I should explicitly call "START TRANSACTION"?
The commit needs to be inside the try block as you want to be sure to rollback if there is no commit. However selects do not require commits.
If autocommit is True on your connection then each insert or update is considered a single transaction and implicitly committed. If autocommit is False then you automatically get transactions and must commit after your inserts. You do not need to call START TRANSACTION if autocommit is false.
If you need to call START TRANSACTION you use conn.begin() documented here:
https://aiomysql.readthedocs.io/en/latest/connection.html#connection
A MySQL transaction is used if you have multiple contingent updates that must all be successful together or rolled back. For example a bank transfer that fails on the second update needs to be rolled back:
Withdraw money from account A
Deposit money in account B
You can find a transaction example in the aiomysql github.
https://github.com/aio-libs/aiomysql/tree/master/examples

SQL overwriting data

I'm trying to learn SQL and using MySQL and I'm just fooling around with it as a hobby. However, I found that in trying to manipulate the data I'm using, a lot of the time I end up overwriting some important information in my records, and I am unable to just ctrl-z this information back.
What are some safety tips when working with SQL that will help me from losing this information. Example, should I always keep a backup copy of all my tables?
Please look at the following link:
http://dev.mysql.com/doc/refman/5.0/en/commit.html
Transactions allow you to Rollback certain blocks of code when something goes wrong during the execution.
You can always prefer writing your SQL queries in START TRANSACTION, COMMIT, and ROLLBACK Syntax
BEGIN and BEGIN WORK are supported as aliases of START TRANSACTION for
initiating a transaction. START TRANSACTION is standard SQL syntax and
is the recommended way to start an ad-hoc transaction.
The advantage of writing your code in transaction is you can rollback your transaction when you want.
Each transaction is stored in the binary log in one chunk, upon
COMMIT. Transactions that are rolled back are not logged.

Mysql insert row ignoring current transaction

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.