MySQL transactions in InnoDB - mysql

I am an MySQL newbie who's learning about transactions, and I'm using the InnoDB engine.
In the MySQL reference manual, I see that they ask to set autocommit to 0 before starting a transaction, but in both ways (setting it to either 0 or 1) I see the same behavior: the transaction is validated after commit and invalidated with Rollback. What is the difference between setting autocommit to 0 or to 1??

There are 3 modes for transactions in InnoDB:
autocommit=1 (or ON): Each statement is a transaction. (See Marc's answer)
autocommit=0 (or OFF): You must eventually issue COMMIT, else changes will be lost. (I see this modes a too error-prone to ever use.)
BEGIN (or START TRANSACTION) ... COMMIT (or ROLLBACK): This explicitly spells out the extent of the transaction. autocommit is ignored. I consider this to be 'best practice'

If autocommit is on, then every query you issue effectively runs like this:
start transaction;
...do a query ...
commit;
start transaction;
... do another query ...
commit
etc...
with autocommit off, there's no automatic transaction, and you start it yourself, which makes the code run like this:
start transaction
...do a query ...
...do another query ...
... etc...
commit;
If you only ever issue single command queries, then there's not much of a difference in behaviors. it's only when you start issuing multiple sequential queries that the new behavior really kicks in.

I think if you use MyISAM storage engine you must set autocommit to 0 but with InnoDB ints not necessary because start transaction sets autocommit to 0 LINK

Related

In InnoDB,is all sql in the transaction?

I seems have a wrong idea that :
update table_name set id=222 where id >333;
my old opinion is above single sql without begin and commit will not start a transaction.
but it seems wrong.
But when i read the mysql doc,i found that seems that all sql will in a transaction.if you do not explicit use begin and commit,it will start transaction implicit in InnoDB.
In InnoDB, all user activity occurs inside a transaction. If autocommit mode is enabled, each SQL statement forms a single transaction on its own. By default, MySQL starts the session for each new connection with autocommit enabled, so MySQL does a commit after each SQL statement if that statement did not return an error. If a statement returns an error, the commit or rollback behavior depends on the error. See Section 14.21.4, “InnoDB Error Handling”.
my question :
Is all sql will ececute in the transaction ,no matter whether do you use begin and commit explicitly.
it will be executed in single transactions - unless grouping statements with START TRANSACTION & COMMIT (the autocommit configuration will then be ignored, no matter it's value). SET autocommit = 0/1 can be used to control the level of isolation on-the-fly. there's also a configuration option for that, in order to change the behavior globally:
[mysqld]
autocommit=0
the documentation for "Server System Variables" explains it in detail:
The autocommit mode. If set to 1, all changes to a table take effect immediately. If set to 0, you must use COMMIT to accept a transaction or ROLLBACK to cancel it. If autocommit is 0 and you change it to 1, MySQL performs an automatic COMMIT of any open transaction. Another way to begin a transaction is to use a START TRANSACTION or BEGIN statement.

Does MySQL use transaction in a single DML modified data with autocommit?

I'm confused with transaction and autocommit. But there's no documents explains what MySQL autocommit do.
If autocommit on, every INSERT UPDATE DELETE statement will take effect immediately. Does MySQL auto start a transaction to do this?
If not, what's MySQL do? What's the difference to transaction?
In my view:
A statement
INSERT INTO ...
with autocommit on equals to
START TRANSACTION;
INSERT INTO ...;
COMMIT;
with autocommit off.
The two statements in anytime any condition takes the same action.
Is it right?
firstly, you have to know, that most MySQL Storage Engines do not support transactions. for example, InnoDB supports, but MyISAM - not.
In InnoDB, you can use transactions by 2 way:
implicit
START TRANSACTION;
INSERT/UPDATE/DELETE
COMMIT;
explicit
via SET autocommit off
both of them provide the same result

Does setting autocommit=0 within a transaction do anything?

I am reviewing code by another developer. He has a commit that explicitly adds set autocommit=0 at the start of a MySQL transaction. This is causing problems for other non-transactional queries in the session.
Does adding set autocommit=0 within a transaction do anything for that transaction? I assume it doesn't, since transactions implicitly do this anyway.
[The only rationale I can come up with for this commit is perhaps the db once used MyISAM (versus the current InnoDB), and this was maybe a way to mimic transactions in the former?]
If a transaction is active, it is not affected by SET autocommit = 0.
Otherwise, if the former value of autocommit was 1, SET autocommit = 0 starts a new transaction.
If you are using MariaDB and you are in doubt, you can check the in_transaction variable.
From the MySQL Reference:
After disabling autocommit mode by setting the autocommit variable to
zero, changes to transaction-safe tables (such as those for InnoDB or
NDB) are not made permanent immediately. You must use COMMIT to store
your changes to disk or ROLLBACK to ignore the changes.
Setting autocommit=0 will modify the entire session.
Transactions and non-transactional commands will need to explictly committed to affect the DB.

Difference between SET autocommit=1 and START TRANSACTION in mysql (Have I missed something?)

I am reading up on transactions in MySQL and am not sure whether I have grasped something specific correctly, and I want to be sure I understood that correctly, so here goes. I know what a transaction is supposed to do, I'm just not sure whether I understood the statement semantics or not.
So, my question is, is anything wrong, (and, if that is the case, what is wrong) with the following:
By default, autocommit mode is enabled in MySQL.
Now, SET autocommit=0; will begin a transaction, SET autocommit=1; will implicitly commit. It is possible to COMMIT; as well as ROLLBACK;, in both of which cases autocommit is still set to 0 afterwards (and a new transaction is implicitly started).
START TRANSACTION; will basically SET autocommit=0; until a COMMIT; or ROLLBACK; takes place.
In other words, START TRANSACTION; and SET autocommit=0; are equivalent, except for the fact that START TRANSACTION; does the equivalent of implicitly adding a SET autocommit=1; after COMMIT; or ROLLBACK;
If that is the case, I don't understand http://dev.mysql.com/doc/refman/5.5/en/set-transaction.html#isolevel_serializable - seeing as having an isolation level implies that there is a transaction, meaning that autocommit should be off anyway?
And if there is another difference (other than the one described above) between beginning a transaction and setting autocommit, what is it?
Being aware of the transaction (autocommit, explicit and implicit) handling for your database can save you from having to restore data from a backup.
Transactions control data manipulation statement(s) to ensure they are atomic. Being "atomic" means the transaction either occurs, or it does not. The only way to signal the completion of the transaction to database is by using either a COMMIT or ROLLBACK statement (per ANSI-92, which sadly did not include syntax for creating/beginning a transaction so it is vendor specific). COMMIT applies the changes (if any) made within the transaction. ROLLBACK disregards whatever actions took place within the transaction - highly desirable when an UPDATE/DELETE statement does something unintended.
Typically individual DML (Insert, Update, Delete) statements are performed in an autocommit transaction - they are committed as soon as the statement successfully completes. Which means there's no opportunity to roll back the database to the state prior to the statement having been run in cases like yours. When something goes wrong, the only restoration option available is to reconstruct the data from a backup (providing one exists). In MySQL, autocommit is on by default for InnoDB - MyISAM doesn't support transactions. It can be disabled by using:
SET autocommit = 0
An explicit transaction is when statement(s) are wrapped within an explicitly defined transaction code block - for MySQL, that's START TRANSACTION. It also requires an explicitly made COMMIT or ROLLBACK statement at the end of the transaction. Nested transactions is beyond the scope of this topic.
Implicit transactions are slightly different from explicit ones. Implicit transactions do not require explicity defining a transaction. However, like explicit transactions they require a COMMIT or ROLLBACK statement to be supplied.
Conclusion
Explicit transactions are the most ideal solution - they require a statement, COMMIT or ROLLBACK, to finalize the transaction, and what is happening is clearly stated for others to read should there be a need. Implicit transactions are OK if working with the database interactively, but COMMIT statements should only be specified once results have been tested & thoroughly determined to be valid.
That means you should use:
SET autocommit = 0;
START TRANSACTION;
UPDATE ...;
...and only use COMMIT; when the results are correct.
That said, UPDATE and DELETE statements typically only return the number of rows affected, not specific details. Convert such statements into SELECT statements & review the results to ensure correctness prior to attempting the UPDATE/DELETE statement.
Addendum
DDL (Data Definition Language) statements are automatically committed - they do not require a COMMIT statement. IE: Table, index, stored procedure, database, and view creation or alteration statements.
In InnoDB you have START TRANSACTION;, which in this engine is the officialy recommended way to do transactions, instead of SET AUTOCOMMIT = 0; (don't use SET AUTOCOMMIT = 0; for transactions in InnoDB unless it is for optimizing read only transactions). Commit with COMMIT;.
You might want to use SET AUTOCOMMIT = 0; in InnoDB for testing purposes, and not precisely for transactions.
In MyISAM you do not have START TRANSACTION;. In this engine, use SET AUTOCOMMIT = 0; for transactions. Commit with COMMIT; or SET AUTOCOMMIT = 1; (Difference explained in MyISAM example commentary below). You can do transactions this way in InnoDB too.
Source: http://dev.mysql.com/doc/refman/5.6/en/glossary.html#glos_autocommit
Examples of general use transactions:
/* InnoDB */
START TRANSACTION;
INSERT INTO table_name (table_field) VALUES ('foo');
INSERT INTO table_name (table_field) VALUES ('bar');
COMMIT; /* SET AUTOCOMMIT = 1 might not set AUTOCOMMIT to its previous state */
/* MyISAM */
SET AUTOCOMMIT = 0;
INSERT INTO table_name (table_field) VALUES ('foo');
INSERT INTO table_name (table_field) VALUES ('bar');
SET AUTOCOMMIT = 1; /* COMMIT statement instead would not restore AUTOCOMMIT to 1 */
https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html
The correct way to use LOCK TABLES and UNLOCK TABLES with transactional tables, such as InnoDB tables, is to begin a transaction with SET autocommit = 0 (not START TRANSACTION) followed by LOCK TABLES, and to not call UNLOCK TABLES until you commit the transaction explicitly. For example, if you need to write to table t1 and read from table t2, you can do this:
SET autocommit=0;
LOCK TABLES t1 WRITE, t2 READ, ...;... do something with tables t1 and t2 here ...
COMMIT;
UNLOCK TABLES;
If you want to use rollback, then use start transaction and otherwise forget all those things,
By default, MySQL automatically commits the changes to the database.
To force MySQL not to commit these changes automatically, execute following:
SET autocommit = 0;
//OR
SET autocommit = OFF
To enable the autocommit mode explicitly:
SET autocommit = 1;
//OR
SET autocommit = ON;

Rails transactions

I am trying to use ActiveRecord::Base.transaction. I figured that rollback doesn't work by default using Rails 1.2.6 and mysql 5.0. Playing with it a little bit more I found out that autocommit is not set to 0 in mysql connection.
Questions:
1) How do I disable autocommit in rails for all connections?
2) Will it have some negative impact on the other code that doesn't have to be transactional?
If you have a mix of code that needs explicit transactions and code that can rely on autocommit, perhaps you shouldn't disable autocommit for all connections. You're on the right track wondering if this will impact other code. If you disable autocommit, but the other code doesn't know it has to commit to have its work committed, then that'll be a problem. Uncommitted work is rolled back when the connection closes.
You should be aware that the default storage engine for MySQL is MyISAM, which doesn't support transactions at all. When you make changes to a table that uses MyISAM, the changes are effectively committed immediately, regardless of your explicit requests to begin and finish transactions, and regardless of the state of autocommit. So you won't be able to roll back no matter what, unless you created your tables using the InnoDB storage engine (or other transaction-safe storage engines such as BDB).
It's unnecessary to disable autocommit mode to use transactions in MySQL. Simply begin a transaction explicitly. The following SQL statements will be part of a transaction until you commit or rollback that transaction, regardless of the value of autocommit on your current connection.
http://dev.mysql.com/doc/refman/5.0/en/commit.html says:
With START TRANSACTION, autocommit
remains disabled until you end the
transaction with COMMIT or ROLLBACK.
The autocommit mode then reverts to
its previous state.
You don't have to disable autocommit to use transactions. When you START a transaction autocommit setting doesn't make any difference, you have to COMMIT or ROLLBACK explicitly. Moreover disabling autocommit will impact your non-transactional code.
Right answer. I was doing DROP TABLE IF EXISTS in my code in the beginning of the transactions. MySQL seems to have a problem with DROP statements within a transaction:
http://bugs.mysql.com/bug.php?id=989
Funny enough that I've guessed correct work-around for the problem sending "SET aucotommit = 0" before the DROP statement.
Thank you for your help
Not that I have any specifically not transactional code - it is mostly all ActiveRecord objects, I just want to have rollback behavior if one of my methods fails.
I will explore more , you seem to be right - I can confirm your answer in mysql console. However in my Rails application I have to do connection.execute("set autocommit = 0") to get rollback working.