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.
Related
I have to update a big table (products) in a MySQL database, every 10 minutes with PHP. I have to run the PHP script with cron job, and I get the most up to date products from a CSV file. The table has currently ~18000 rows, and unfortunately I can not tell how much it will change in a 10 min period. The most important thing is of course I do not want the users to notice the update in the background.
These are my ideas and fears:
Idea1: I know that there is a way to load a csv file into a table with MySQL, so maybe I can use a transaction to truncate the table, and import the CSV. But even if I use transactions, as long as the table is large, I'm afraid that there will be a little chance for some users to see the empty database.
Idea2: I could compare the old and the new csv file with a library and only update/add/remove the changed rows. This way I think there it's not possible for a user to see an empty database, but I'm afraid this method will cost a lot of RAM and CPU, and I'm on a shared hosting.
So basically I would like to know which method is the most secure to update a table completely without the users noticing it.
Assuming InnoDB and default isolation level, you can start a transaction, delete all rows, insert your new rows, then commit. Before the commit completes, users will see the previous state.
While the transaction is open (after the deletes), updates will block, but SELECTs will not. Since it's a read only table for the user, it won't be an issue. They'll still be able to SELECT while the transaction is open.
You can learn the details by reading about MVCC. The gist of it is that any time someone performs a SELECT, MySQL uses the data in the database plus the rollback segment to fetch the previous state until the transaction is committed or rolled back.
From MySQL docs:
InnoDB uses the information in the rollback segment to perform the
undo operations needed in a transaction rollback. It also uses the
information to build earlier versions of a row for a consistent read.
Only after the commit completes will the users see the new data instead of the old data, and they won't see the new data until their current transaction is over.
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.
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.
I am making a webservice in PHP which does a series of calculations based on a select from a table and then updates the table afterwards with the new results.
However i want to prevent the case where another person is making a call to the same webservice while another person's session is still doing an update.
Is it the right thing here to lock that entire table and then unlock it again? If so, how do i lock and unlock a mysql table using PHP pdo?
Database Management Systems like MySQL are smart enough to prevent concurrency violations like these.
Look for database isolation levels (read uncommitted, read commited, repeatable read, serializable) and the possible problems (dirty read, non repeatable read ...) -> Wikipedia.
Personally, I would not recommend a table lock in your case. You better wrap your calculations and database operations in a transaction and rely on the DBMS to manage your stuff.
I posted a comment:
Not a direct answer, but I don't think this is any problem. The
calculations and fetching data from the database is done within a few
milliseconds. The chances or two people interacting at the same time
is soooo small that most people don't bother making a lock like this.
But if these calculations are critical you could prevent this problem by adding a new field and simply call it occupied, busy or something like that.
When you run your script, check if this field is set to for example 1, if it is, make the script sleep for 1-2-3 seconds and then retry. If this field is set to 0, update it to 1, do the calculations and set it back to 0 again.
This would prevent two people from accessing the same values at the same time.
When I save an array of records i.e multiple records, if one of the records in the middle has an error(sql), what will happen? Will all records henceforth not be inserted or just the current row or none of them? How should I handle the situation?
PDO Driver is Mysql
Take a look at PDO-Transactions: http://php.net/manual/en/pdo.begintransaction.php
You can check whether there was an error, and if so rollback your commits or do whatever you intend to do
These situations are managed with database transactions.
The classical example is when I want to transfer money from my account to another account. There are two queries to be done:
Remove the money from my account
Put the money in the other account
Of course if the second query fails, I want the first one to be rolled back and notify the user of the error. That's what transactions are for.
If you don't use transactions, when the second query fails, the first is executed anyway and not rolled back (so the money disappears). This is the default behaviour of MySQL.
The general solution would be to use TRANSACTION (mysql) (pgsql) (mssql). What you can do with it and how much control you have, depends on RDBMS. For example: PostgreSQL lets you create a SAVEPOINT, to which you can ROLLBACK TO.
Another solutions would be to use STORED PROCEDURE. In that case you can can specify what should happen if error occurs with DECLARE .. HANDLER