how to delay PHP script until Mysql insert query is committed - php

In the website I am developing the Users have to sign Up or register.
when the users submits the form for registration the user should get logged automatically with his UserName...
Now, I insert the data into Mysql database followed by retrieving the same data from database with Select statement but the problem is that Select statement is executed faster then the Insert (or something) and it results in Fatal error... I want the PHP script for retrieving data wait until the Insertion is committed... How can I do that ? thanks

First check whether query has been executed successfully or not.
$result = mysql_query('SELECT * WHERE 1=1');
if (!$result) {
die('Invalid query: ' . mysql_error());
}

Using PHP, requests to a RDBMS such as MySQL are always performed synchronously. Then, the behaviour you describe might come from a not-commited transaction initiated prior your INSERT SQL statement. Indeed, if the transaction is not finished and you perform a SELECT SQL statement on the previously inserted table, you will see nothing new because the RDBMS does not know yet if the inserted data must commited or not.
The first thing you might want to check is whether or not a transaction is begun:
Look in the execution stack if an SQL transaction is begun prior your call to INSERT.
Check if the configuration parameter autocommit is set or not (see https://dev.mysql.com/doc/refman/5.0/en/commit.html).
If you are not performing formal transactions in your code, enabling autocommit might be a solution. Otherwise, simply do not forget to send a COMMIT statement when appropriate.

I am facing a similar problem.
After being unable to fix it properly, i've ended UP adding a sleep(1); after my INSERT/UPDATE query.
It seems that the server may not been working properly, because queries are executed syncronous. Im feeling that my problem is related to memory or filesystem/cache delays at VPS. Data takes around 0.100 to be really updated, when it should be reflected at runtime.
I am not sure where the problem really comes, just telling you "how to delay PHP script".
Regards.

Related

Using MySQL last insert id for the same user

I'm using the mysql_insert_id within my code to get an auto increment.
I have read around and it looks like there is no race condition regarding this for different user connections, but what about the same user? Will I be likely to run into race condition problems when connecting to the database using the same username/user but still from different connection sessions?
My application is PHP. When a user submits a web request my PHP executes code and for that particular request/connection session I keep a persistent SQL connection open in to MySQL for the length of that request. Will this cause me any race condition problems?
None for any practical purpose, If you execute the last_id request right after executing your insert then there is practically not enough time for another insert to spoil that. Theoretically might be
possible
According to PHP Manual
Note:
Because mysql_insert_id() acts on the last performed query, be sure to
call mysql_insert_id() immediately after the query that generates the
value.
Just in case you want to double check you can use this function to confirm your previous query
mysql_info
The use of persistent connections doesn't mean that every request will use the same connection. It means that each apache thread will have its own connection that is shared between all requests executing on that thread.
The requests will run serially (one after another) which means that the same persistent connection will not be used by two threads running at the same time.
Because of this, your last_insert_id value will be safe, but be sure that you check the result of your inserts before using it, because it will return the last_insert_id of the last successful INSERT, even if it wasn't the last executed INSERT.

How exactly do transactions with PHP PDO work with concurrency?

I'm making a webapp where they'll be multiple users interacting with each other and reading/making decisions on/modifying shared data.
I've read that transactions are atomic, which is what I need. However, I'm not sure how it works with the PHP PDO::beginTransaction()
I mean atomic as in if one transaction is editing some data, all other transactions also modifying/reading that data will need to wait until the first transaction finishes. Like I don't want two scripts reading a value, incrementing the old one, and effectively storing only one increment. The second script should have to wait for the first one to finish.
In almost all the examples I've seen the queries are used consecutively (example PHP + MySQL transactions examples). A lot of what I'm doing requires
querying and fetching
checking that data, and acting on it, as part of the same transaction
Will the transaction still work atomically if there is PHP code between queries?
I know you should prepare your statements outside the transaction, but is it okay to prepare it inside? Basically, I'm worried about PHP activity ruining the atomicity of a transaction.
Here's an example (this one doesn't require checking a previous value). I have a very basic inbox system which stores mail as a serialized array (if someone has a better recommendation please let me know). So I query for it, append the new message, and store it. Will it work as expected?
$getMail = $con->prepare('SELECT messages FROM inboxes WHERE id=?');
$storeMail = $con->prepare('UPDATE inboxes SET messages=? WHERE id=?');
$con->beginTransaction();
$getMail->execute(array($recipientID));
$result = $getMail->fetch();
$result = unserialize($result[0]);
$result[] = $msg;
$storeMail->execute(array(serialize($result), $recipientID));
$con->commit();
Transactions are atomic only with respect to other database connections trying to use the same data, i.e. other connections will see either no changes made by your transaction, or all changes; "atomic" meaning no other database connection will see an in-between state with some data updated and other not.
PHP code between queries won't break atomicity, and it does not matter where you prepare your statements.

mysql row locking via php

I am helping a friend with a web based form that is for their business. I am trying to get it ready to handle multiple users. I have set it up so that just before the record is displayed for editing I am locking the record with the following code.
$query = "START TRANSACTION;";
mysql_query($query);
$query = "SELECT field FROM table WHERE ID = \"$value\" FOR UPDATE;";
mysql_query($query);
(okay that is greatly simplified but that is the essence of the mysql)
It does not appear to be working. However, when I go directly to mysql from the command line, logging in with the same user and execute
START TRANSACTION;
SELECT field FROM table WHERE ID = "40" FOR UPDATE;
I can effectively block the web form from accessing record "40" and get the timeout warning.
I have tried using BEGIN instead of START TRANSACTION. I have tried doing SET AUTOCOMMIT=0 first and starting the transaction after locking but I cannot seem to lock the row from the PHP code. Since I can lock the row from the command line I do not think there is a problem with how the database is set up. I am really hoping that there is some simple something that I have missed in my reading.
FYI, I am developing on XAMPP version 1.7.3 which has Apache 2.2.14, MySQL 5.1.41 and PHP 5.3.1.
Thanks in advance. This is my first time posting but I have gleaned alot of knowledge from this site in the past.
The problem is not the syntax of your code, but the way you are trying to use it.
just before the record is displayed for editing I am locking the record with the following code
From this I am assuming that you select and "lock" the row, then display that edit page to your user, then when they submit the changes it saves and "unlocks" the table. Here in lies the fundamental problem. When your page is done loading, the PHP exits and closes the MySQL connection. When this happens, all the locks are immediately released. This is why the console seems to behave differently than your PHP. The equivalent in the console would be you exiting the program.
You cannot lock the table rows for editing for an extended period. This is not their design. If you want to lock a record for editing, you need to track these locks in another table. Create a new table called "edit_locks", and store the record id being locked, the user id editing, and the time it was locked. When you want to open a record for editing, lock the entire edit_locks table, and query to see if the record is locked by someone else. If it is not, insert your lock record, if it is, then display a locked error. When the user saves or cancels, remove the lock record from edit_locks. If you want to make things easy, just lock this table any time your program wants to use it. This will help you to avoid a race condition.
There is one more scenario that can cause a problem. If the user opens a record for editing, then closes the browser without saving or canceling, the edit lock will just stay there forever. This is why I said store the time it was locked. The editor itself should make an AJAX call every 2 minutes or so to say "I still need the lock!". When the PHP program receives this "relock" request, it should search for the lock, then update the timestamp to the current. This way the timestamp on the lock is always up to date within 2 minutes. You also need to create another program to remove old stale locks. This should run in a cron job every few minutes. It should search for any locks with a timestamp older than 5 minutes or so, and remove. If the timestamp is older than that, then clearly the editor was close some how or the timestamp would be up to date within 2 minutes.
Like some of the others have mentioned, you should try to use mysqli. It stands for "MySQL Improved" and is the replacement for the old interface.
This is an old discussion, but perhaps people are still following it. I use a method similar to JMack's but include the locking information in the table I want to row-lock. My new columns are LockTime and LockedBy. To attempt a lock, I do:
UPDATE table
SET LockTime='$now',LockedBy='$Userid'
WHERE Key='$value' AND (LockTime IS NULL OR LockTime<'$past' OR LockedBy='$Userid')
($past is 4 minutes ago)
If this fails, someone else has the lock. I can explicitly unlock as follows or let my lock expire:
UPDATE table
SET LockTime=NULL,LockedBy=''
WHERE Key='$value' AND LockedBy='$Userid'
A cron job could remove old locks, but it's not really necessary.
Use PDO for this (and all database operations):
$value = 40;
try {
$dbh = new PDO("mysql:host=localhost;dbname=dbname", 'username', 'password');
} catch (PDOException $e) {
die('Could not connect to database.');
}
$dbh->beginTransaction();
try {
$stm = $dbh->prepare("SELECT field FROM table WHERE ID = ? FOR UPDATE");
$stm->execute(array($value));
$dbh->commit();
} catch (PDOException $e) {
$dbh->rollBack();
}
If you must use the antiquated mysql_* functions you can something like:
mysql_query('SET AUTOCOMMIT=0');
mysql_query('START TRANSACTION');
mysql_query($sql);
mysql_query('SET AUTOCOMMIT=1');
You should not use the mysql api because it's easy to make mistakes that enables sql-injections and such, as well as it lacks some functionality. I suspect that transaction is one of these because if i'm not wrong every query is sent "by itself" and not in a larger context.
The solution however is to use some other api, i prefer mysqli because its so similar to mysql and widely supported. You can easily rewrite your code to use mysqli instead as well.
For the transaction functionality set auto-commit to false and commit yourself when you want it to. This does the same as starting and stopping transactions.
For the reference look at:
http://www.php.net/manual/en/mysqli.autocommit.php
http://www.php.net/manual/en/mysqli.commit.php
the problem are the mysql commands. You could use mysqli for this
http://nz.php.net/manual/en/class.mysqli.php
or PDO. Described here:
PHP + MySQL transactions examples
HTH

Can I use a database value right after I insert it?

Can I insert something into a MySQL database using PHP and then immediately make a call to access that, or is the insert asynchronous (in which case the possibility exists that the database has not finished inserting the value before I query it)?
What I think the OP is asking is this:
<?
$id = $db->insert(..);
// in this case, $row will always have the data you just inserted!
$row = $db->select(...where id=$id...)
?>
In this case, if you do a insert, you will always be able to access the last inserted row with a select. That doesn't change even if a transaction is used here.
If the value is inserted in a transaction, it won't be accessible to any other transaction until your original transaction is committed. Other than that it ought to be accessible at least "very soon" after the time you commit it.
There are normally two ways of using MySQL (and most other SQL databases, for that matter):
Transactional. You start a transaction (either implicitly or by issuing something like 'BEGIN'), issue commands, and then either explicitly commit the transaction, or roll it back (failing to take any action before cutting off the database connection will result in automatic rollback).
Auto-commit. Each statement is automatically committed to the database as it's issued.
The default mode may vary, but even if you're in auto-commit mode, you can "switch" to transactional just by issuing a BEGIN.
If you're operating transactionally, any changes you make to the database will be local to your db connection/instance until you issue a commit. Issuing a commit should block until the transaction is fully committed, so once it returns without error, you can assume the data is there.
If you're operating in auto-commit (and your database library isn't doing something really strange), you can rely on data you've just entered to be available as soon as the call that inserts the data returns.
Note that best practice is to always operate transactionally. Even if you're only issuing a single atomic statement, it's good to be in the habit of properly BEGINing and COMMITing a transaction. It also saves you from trouble when a new version of your database library switches to transactional mode by default and suddenly all your one-line SQL statements never get committed. :)
Mostly the answer is yes. You would have to do some special work to force a database call to be asynchronous in the way you describe, and as long as you're doing it all in the same thread, you should be fine.
What is the context in which you're asking the question?

Dependent insertion of data into MySql table

I have 2 tables:
user_tb.username
user_tb.point
review_tb.username
review_tb.review
I am coding with PHP(CodeIgniter). So I am trying to insert data into review_tb with the review the user had submitted and if that is a success, i will award the user with some points.
Well this look like a very simple process. We will first insert the review into the review_tb with the username and use PHP to check if there is any problem with the query executed and if it's a success, we will proceed with updating the points in the user_tb.
Yea, but here comes the problem. What if inserting into review_tb is a success but the second query, inserting into the user_tb is NOT a success, can we kind of "undo" the review_tb query or "revert" the change that we did to review_tb.
It's kind of like "all or nothing".
The purpose of this is to sync all data across the database, where in real life, we will be managing a database of more tables, and inserting more data into each table which depends on each other.
Please give some enlightenment on how we can do this in PHP or CodeIgniter or just MySql query.
If you want a "all or nothing" behavior for your SQL operations, you are looking for transactions ; here is the relevant page from the MySQL manual : 12.4.1. START TRANSACTION, COMMIT, and ROLLBACK Syntax.
Wikipedia describes those this way :
A database transaction comprises a
unit of work performed within a
database management system (or
similar system) against a database,
and treated in a coherent and reliable
way independent of other transactions.
Transactions in a database environment
have two main purposes:
To provide reliable units of work that allow correct recovery from
failures and keep a database
consistent even in cases of system
failure, when execution stops
(completely or partially) and many
operations upon a database remain
uncompleted, with unclear status.
To provide isolation between programs accessing a database
concurrently. Without isolation the
programs' outcomes are typically
erroneous.
Basically :
you start a transaction
you do what you have to ; ie, your first insert, and your update
if everything is OK, you commit the transaction
else, if there is any problem with any of your queries, you rollback the transaction ; and it will cancel everything you did in that transaction.
There is a manual page about transactions and CodeIgniter here.
Note that, with MySQL, no every Engine supports transaction ; between the two most used engines, MyISAM doesn't support transactions, while InnoDB supports them.
Can't you use transactions? If you did both inserts inside the same transaction, then either both succeed or neither does.
Try something like
BEGIN;
INSERT INTO review_tb(username, review) VALUES(x, y);
INSERT INTO user_tb(username, point) VALUES(x, y);
COMMIT;
Note that you need to use a database engine that supports transactions (such as InnoDB).
If you have InnoDB support use it, but when its not possible you can use a code similar to the following:
$result=mysql_query("INSERT INTO ...");
if(!$result) return false;
$result=mysql_query("INSERT INTO somewhereelse");
if(!$result) {
mysql_query("DELETE FROM ...");
return false;
}
return true;
This cleanup might still fail, but can work whenever the insert query fails because of duplicates or constraints. For unexpected terminations, only way is to use transactions.

Categories