Rollback and roll-forward except one transaction with MySQL and InnoDB - php

I currently use InnoDB transactions to manage the effect of any single webpage request. One request per transaction. This works well if the request fails I can just ignore it.
As a relative newbie to MySQL administration, I remain worried that something I write into my PHP code will do something bad to my database. DELETE FROM or UPDATE without a where statement or something as an extreme example. The idea of the transactions is that when I inevitably notice what happened later, after the bad transaction is committed, I should be able to rollback the mistake.
However, the database is used heavily, so its likely that other transactions will come in between when I commit the bad transaction and when I notice it and go to act on it. But all the documentation I have seen on transactions, and the AWS restore-to-point-in-time, only allow you "go back" to before a transaction is committed.
So, how do I recover or "roll-forward" the transactions that came in after my bad one? They are in the InnoDB log, so should I be able to apply the later transactions again, just skipping the one bad one? My software interfaces with an external credit card processor, so just losing those later transactions isn't an option.
I have a hard time imagining its impossible, but I can't find any way to "roll-forward". Is this possible? Is it something you have to write into the database structure itself, like keeping a history table with triggers and using a history record to update after rolling back?
Confused.

Related

How can I prevent concurrency while writing and reading from my DB?

I have a table with user login information and registration too. So when two users consecutively try to add their details:
Will both the writes clashes and the table wont be updated?
Using threads for these writes is bad idea. As for each write a new thread would be created and it would clog the server. Is the server responsible for it to manage on its own?
Is locking the table a good idea?
My back-end runs on PHP/Apache with MySQL (InnoDB) for the database.
Relational databases are designed to avoid these kinds of conditions. You don't need to worry about them unless you are designing your own relational database from scratch.
In short, just know this: Any time a write is initiated, there is a row-level lock. If another transaction wants to write to that same row, then it has to wait until the first transaction releases the lock. This is a fundamental part of relational databases. You don't need to add a lock because they've already thought of that :)
You can read more about how MySQL performs locks to avoid deadlocking and other transaction errors here.
If you're really paranoid about this, or perhaps you are doing multiple things when you register a user and need them done atomically, you might want to look at using Transactions in MySQL. There's a decent write-up about Transactions here http://www.mysqltutorial.org/mysql-transaction.aspx
BEGIN;
do related reads/writes to the data
COMMIT;
Inside that "transaction", the connection sees a consistent view of the data, and blocks anyone else from messing with that view.
There are exceptions. The main one is
BEGIN
SELECT ... FOR UPDATE;
fiddle with the values SELECTed
UPDATE ...; -- and change those values
COMMIT;
The SELECT .. FOR UPDATE announces what should not be tampered with. If another connection wants to mess with the same rows, it will have to wait until your COMMIT, at which time he may find that things have changed and he will need to do something different. But, in general, this avoids a "deadlock" wherein two transactions are stepping on each other so badly that one has to be "rolled back".
With techniques like this, the "concurrency" is prevented only briefly and relatively precisely. That is, if two connections are working with different rows, both can proceed -- there is no need to "prevent concurrency".

PHP/Laravel rolling back transaction later in time?

Is there a way to roll back a transaction later in time? I want to make a function, where the user can upload an excel file and than the data it contains converted into sql inserts inside a transaction. If there is an error, I can roll back the transaction, but I also would like to be able to roll it back when the user wants to. So, basically it is an UNDO LAST SESSION/UPLOAD function to this section.
I am using PHP5.4, Laravel 4.2 and MySQL5.5
Rollback is a technical term in database operations; it has a precise meaning related to transactions.
What you're proposing to do doesn't sound like a rollback. It sounds like deleting rows--deleting rows at an arbitrary time. (Arbitrary time, because last session could be hours or days or weeks ago, right?)
As long as you know which keys are involved--and that might not be a simple thing to do--you can delete rows by using the keys. And you can do this regardless of the dbms and regardless of the ORM or web framework.
One complication in the general case is that committed rows are visible to other transactions. So other transactions--and other users--might use some of your rows in foreign key references. This will greatly complicate deleting rows.

Why using innoDB and transactions?

So I wanted to start a browser game project. Just for practise.
After years of PHP programming, today I heard about transactions and innoDB the first time ever.
So I googled it and still have some questions.
My first encounter with it was on a website that says, InnoDB would be necessary when programming a browsergame. Because it might be used by many people at the same time and if two people access to a database table at the same time (with one nanosecond difference for example), it could get confusing and data might be lost or your SELECT is not updated although it should have been updated by the access one nanosecond ago (but the script was still running and couldn't change it yet) ... and so on.
And apparently, transactions solve this problem by first handling the first access (until it is completed) and then handling the second one. Is this correct?
And another function is, that if you have for example 2 queries in your transaction and the second one fails, it "rolls back" and "deletes"(or never applies) the changes of the first (successful) query. Right? So either everything goes as it should or nothing changes at all. That would be great I think.
Another question: When should I use transactions? Everytime I access the database? Or is it better to use it just for some particular accesses to the database? And should I always use try {} catch() {}?
And one last question:
How does this transaction proceeds?
My understanding is the following:
You start a transaction
You do your queries and change the database or SELECT something
If everything went well, you commit the changes so they get applied to the database
If something went wrong with queries it cancels and jumps to the catch() {} where you rollback the transaction and the changes don't get applied
Is this correct? Of course, besides the question how to start, commit and rollback a transaction in your code.
Yes this is correct.You can also create savepoints to save your current point before running the query.I stricly recommend you to look into the documentation of mysql references it is explained there clearly.

PDO Transactions Locks?

I have done extensive research about MySQL transactions via the PHP PDO interface. I am still a little fuzzy about the actual background workings of the transaction methods. Specifically, I need to know if there is any reason that I should want to prevent all my queries (SELECTs included) inside a transaction spanning from the beginning of the script to the end? Of course, handling any error in the transaction and rolling them back if need be.
I want to know if there is any locking going on during a transaction and if so, is it row level locking because it is InnoDB?
Don't do that.
The reason for this is that transactions take advantage of MVCC a mechanism by which every piece of data updated is in fact not update-in-place but merely inserted in somewhere else.
MVCC implies allocating memory and or storage space to accumulate and operate all of the changes you send it without committing them to disk until you issue a COMMIT.
That means that while your entire script runs all changes are stored until the script ends. And all of the records that you try and change during the transaction are marked as "work in progress" so that other processes/threads can know that this data will soon be invalidated.
Having certain pieces of data marked as "work in progress" for the entire length of the script means that any other concurrent update will see the flag and say "i have to wait until this finishes so I'll get the most recent data".
This includes SELECTS depending on isolation levels. Selecting stuff that is marked as "work in progress" may not be what you want because some tables that you may want to join may contain already updated data while other tables are not updated yet resulting in a dirty read.
Transactionality and atomicity of operations is desirable but costly. Use it where it's needed. Yes that means more work for you to figure out where race conditions can happen and even if race conditions occur you have to make the decision if they are really critical or is "some" data loss/mix acceptable.
Would you like your logs and visit counters and other statistics to drag down the speed of your entire site? Or is the quality of that information sacrificable for speed (as long as it's not an analytics suit you can afford the occasional collision).
Would you like a seat reservation application to miss-fire and allow more users to grab a seat even after the seat cout was 0? of course not - here you want to leverage transactions and isolation levels to ensure that never happens.

cany understand php oracle function oci_commit()

I read the following in the PHP/Oracle manual from php.net:
A transaction begins when the first SQL statement that changes data is executed with oci_execute() using the OCI_NO_AUTO_COMMIT flag. Further data changes made by other statements become part of the same transaction. Data changes made in a transaction are temporary until the transaction is committed or rolled back. Other users of the database will not see the changes until they are committed.
There are two things that I don't understand:
What is committing for?
What does that mean that "other users of the database will not see the changes until they are committed?" How will not they able to see the changes?
Well, you should read some more about transactions.
Simply put - you can think of any query within a transaction as a draft, a temporary data set, that only you(within your database session/connection) can see, unless you issue a commit.
Another analogical explanation is to think of transactions as your thoughts on something that you would actually write down on paper afterwards. The commit is the act of actually writing it so it no longer exists only in your head.
Committing is the finalization of the transaction in which the changes are made permanent.
Because Oracle has the read consistent view, users that start a transaction will only be able to see data that was committed when the new transaction started. So when user A starts a transaction and user B changes some values in a table and commits it, user A won't see the changed data until user A starts a new transaction. The read consistent view makes sure that all users always see a consistent state, one with all data committed.
This causes that a single block of a table can have multiple versions in the undo tablespace, just to support the read consistent views for various transactions.

Categories