I think I got the principle right I just want to make sure I get it right.
So when autocommit is enabled it means every command I do wont be executed directly, except whose who trigger the commit themselves.
So when I've for example a basic macro running like:
statement.executeUpdate("SET autocommit = 0;")
//some code
//SQL Queries
//SQL DELETEs
//SQL INSERTs
statement.executeUpdate("COMMIT;")
Then what would happen would be - If the script runs through without any problem the script goes to the point where every SQL Statement is executed and COMMITed at the end, if not and an error or exception happens the script breaks at that point never turns to the point where the COMMIT is going to happen and every change prior to that point is undo, so that every deleted information will still be there and every insertion is thrown away.
Is it that simple or did I get something wrong?
Assuming you are using a decent database, the data of the current transaction is not typically stored in the table heap itself but in a "redo log".
That is, it's not even in the table until the commit is executed. The commit and other later processed place them in the main table at some point.
In general, if the database engine crashes, the data may still be on disk somewhere, but not in any "official" table area, so it will be discarded when the database engine is restarted. It did not modify the actual data.
Related
Our production server gets stuck on Init for update state whenever we start a query like
update
<some_big_table>
set
<primary_key> = <some_sequence>.nextval
order by
<some_indexed_field>
While this the query is stuck are this state, all other queries get stuck at commit or writing to binlog state.
I couldn't find any relevant documentation for the same either.
That has to change every row in the table. So it effectively locks the entire table. And it takes a long time.
Hence, it blocks other queries touching the table for any purpose.
As for the "state" -- It is like most states, it does not mean much. And is possibly misleading. (I would expect it to be finished with "init" and "performing" the update.)
I encounter in my project a need to implement transactions - thing that I never did before. I already checked that my aytocommit is set to 1 - and I'm not sure if I nneed to touch it at all?
Right now I have set of scripts that all does include function that connnects to database first. There is a perfect place to put mysqli_begin_transaction($link);, and mysqli_autocommit($link, FALSE);, so I'd have transactions everywhere regardless if specific script does need it, or not, and turn off autocommit - the documentation on php.net if very poor there but AFAIR I should do this. So my question no. 1 & 2 would be: Is it fine to start transaction everywhere regardless if script does need it or not? And should i disable autocommit like this as well?
Now let's say, that I have such script (sorry for not providing actual code, but my question is about how transaction works, not about code itself):
~insert and/or update things
~do something aka "line 2"
~insert and/or update things again
Seems like example taken right from the book. I obviously want all inserts and updates, or none to happen. Since I already started transaction, I assume, that nothing will commit, unless I call mysqli_commit ($link);. But here we have a little problem: I do not include any 'footer' at the end of my scripts and doing so seems like a nightmare now, so I don't have any place to put commit. So question no. 3 is: Will my queries commit automaticly after script ends (or I call exit; or die();) even if i set autocommit to false? Or do I need to call commit/do not turn off autocommit?
Now comes time for case when something fails and I need to rollback. Same as above - do I need to call mysqli_rollback (mysqli $link);, or pure fact that I did not call commit will be sufficient? I'm refering here to an situation where script does not end normally. Situations like power off server while working on "line 2", or was stopped because it took to much time (set_time_limit stopped it).
This is a somewhat broad question, so I'll try to cover all the things as much as I can.
At first you can ignore the mysqli api (the api specific transaction functions are just wrappers), and go straight to the MySQL manual. The important thing here is that disabling autocommit and starting a transaction are the same thing. Also a single query (including modifications by triggers) is always a transaction.
The answer you question 1 & 2 is "probably not". It very much depends on what your existing code assumes about the database connection, and how your application is structured.
From what you mentioned in the question, the answer would be: it will be better if you only put transactions in the places that need them.
For question 3: it will not commit automatically. You can however make it do so, by using register_shutdown_function, although I don't recommend doing that.
There are statements (implicit commits) which will commit the transaction automatically. These include all DDL statements (CREATE,ALTER...) and also TRUCNATE, LOCK TABLES and others. This basically means those statements can't be used in transactions.
MySQL rolls back transactions when the connection is terminated.
I would recommend to add transactions only to the code which needs them (to be safe you can do this for all code which does more than one write query to the db).
The classic approach is:
START TRANSACTION
query
other things
another query
some other stuff
3-rd query
...
COMMIT
The main thing here is to make sure you only commit if no errors have occurred.
Leave the rollback to either connection termination (or register_shutdown_function if you are using persistent connections), because making sure each and every script will have a correctly working rollback logic is hard :)
This will make sure that nothing is committed if bad things happen (exceptions, fatal errors, time/mem limits, power outages, meteors...).
It is also possible to have transactions at a function/method level (nested and stack-like), but thats out of the scope for this question.
I am having trouble finding an answer to this using google or Stack Overflow, so perhaps people familiar with Percona XtraDB can help answer this. I fully understand how unexpected deadlocks can occur as outlined in this article, and the solution is to make sure you wrap your transactions with retry logic so you can restart them if they fail. We already do that.
https://www.percona.com/blog/2012/08/17/percona-xtradb-cluster-multi-node-writing-and-unexpected-deadlocks/
My questions is about normal updates that occur outside of a transaction in auto commit mode. Normally if you are writing only to a single SQL DB and perform an update, you get a last in wins scenario so whoever executes the statement last, is golden. Any other data is lost so if two updates occur at the same time, one of them will take hold and the others data is essentially lost.
Now what happens in a multi master environment with the same thing? The difference in cluster mode with multi master is that the deadlock can occur at the point where the commit happens as opposed to when the lock is first taken on the table. So in auto commit mode, the data will get written to the DB but then it could fail when it tries to commit that to the other nodes in the cluster if something else modified the exact same record at the same time. Clearly the simply solution is to re-execute the update again and it would seem to me that the database itself should be able to handle this, since it is a single statement in auto commit mode?
So is that what happens in this scenario, or do I need to start wrapping all my update code in retry handling as well and retry it myself when this fails?
Autocommit is still a transaction; a single statement transaction. Your single statement is just wrapped up in BEGIN/COMMIT for you. I believe your logic is inverted. In PXC, the rule is "commit first wins". If you start a manual transaction on node1 (ie: autocommit=0; BEGIN;) and UPDATE id=1 and don't commit then on node2 you autocommit an update to the same row, that will succeed on node2 and succeed on node1. When you commit the manual UPDATE, you will get a deadlock error. This is correct behavior.
It doesn't matter if autocommit or not; whichever commits first wins and the other transaction must re-try. This is the reason why we don't recommend writing to multiple nodes in PXC.
Yes, if you want to write to multiple nodes, you need to adjust your code to "try-catch-retry" handle this error case.
I am part of the coding team of a high request game.
We've experienced some problems lately where by multiple requests can be sent in at the exact same time and are syndication duplicate actions (which would not be able to happen if they ran entirely after one another).
The problematic routine calls a row in an InnoDB table and if present continues on it's routine until all other checks are okay and at which point it completes and deletes the row.
What appears to be happening is the reads are hitting the row simultaneously (despite the row level locking) and continuing on down the routine path, by which point the deletes make no difference. What this is causing to happen is that the routine is being duplicated by players smart enough to try their luck.
Does anyone have any suggestions for a way to approach fixing this?
Example routine.
// check database row exists (create the initial lock)
// proceed
// check quantity in the row
// if all is okay (few other checks needed here)
// delete the row
// release the lock either way (for the next request to go through)
MySQL has a couple different lock modes
http://dev.mysql.com/doc/refman/5.6/en/innodb-lock-modes.html
I think you'll want to enforce an exclusive lock when executing an update/delete. This way the subsequent requests will wait until the lock is released and the appropriate action has completed.
You may also want to examine the indexes being used for these concurrent queries. An appropriate indexing regime will minimize the number of rows that need to be locked during a given query.
I wrote a tool for our project, for applying sql update files that were committed, to the DB. Whenever run (on deployment), it calculates the list of update files which need to be applied, and applies them iniside a transaction.
Recently I became aware of an issue: mysql would implicitly commit a transaction, whenever DDL statements (like create) are executed. http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html
This is an issue for me, as sometimes an sql update file contains several statements, which as I understand will result in committing the transaction in the middle of executing the update file. This is a problem, because whenever a subsequent update will fail (which happens from time to time) I want to be able to rollback the transaction, or at least track which update files where applied (completely) and which were not.
Is there a way around the implicit transactions issue? I.e. is there a way to rollback a sequence of DDL statements whenever one of them fail?
Any other suggestions how I can handle the issue?
Thanks
Gidi
No. MySQL does not support transactional DDL. You either need to separate your DDL statements from DML statements, or perhaps try to use migration tool like RuckUsing