I got a very weird problem with oracle today.
I setup a new server with xampp for developing, i activated mssql and oracle and everything was just fine until i tried to execute an update statement.
Every select, insert, etc is working fine with PHP 5.3.
I also can parse the statement and get a ressource id back, but when i try to execute the statement my whole site is not responding.
no error, nothing. just timeout until i restart the apache.
here the code... it's the test code, so there should be no problem at all.
$conn = oci_connect('***', '***', '***');
$query ="UPDATE CHAR*** SET TPOS = 14, ID = 5, DIFF = 'J' WHERE ***NR = '3092308' AND LA*** = '5'";
echo $query;
echo '<br>';
echo $stid = oci_parse($conn, $query);
oci_execute($stid, OCI_DEFAULT);
oci_free_statement($stid2);
Any hints or ideas? :-(
I already tried to reinstall the oracle instant client and another version. I am using 10g like our db at the moment.
best regards
pad
The row may be locked by another session. If this is the case, your session will hang until the other transaction ends (commit/rollback).
You should do a SELECT FOR UPDATE NOWAIT before attempting to update a row (pessimistic locking):
If the row is locked, you will get an error and can return a message to the user that this record is currently being updated by another session. In most cases an explicit message is preferable to indefinite waiting.
If the row is available, you will make sure no session modifies its content until you commit (and thus you will prevent any form of lost update).
There are other reasons why a simple update may take a long time but they are less likely, for instance:
When you update an unindexed foreign key, Oracle needs to acquire a lock on the whole parent table for a short time. This may take a long time on a busy and/or large table.
There could be triggers on the table that perform additional work.
For further reading: pessimistic vs optimistic locking.
Related
Under plain PHP 5.3, I have some code which uses MySQL to first deletes some old records, record a log, perform a few tiny operations and then adds new replacement records.
The delete command looks like this:
DELETE FROM `rtable` WHERE `UserName`='%s';
And the add commands looks like this:
INSERT INTO `table` (`UserName`,`Attribute`,`op`,`Value`) VALUES ('%s','%s','%s','%s');
Oddly though, the insert commands appear to not execute when running normally, however if I enable my debugger and step through one line at a time, it appears to work. Likewise, if I insert a sleep command of two seconds after the delete commands. It appears to work. I am therefor assuming that the insert commands are running -before- the delete commands and thus the delete commands are also erasing the new records.
How can I get PHP to wait for the delete operation to finish before continuing to the insert commands?
That sounds really odd.
Do you happen to have a replicated database cluster?
Also, do you check the return value of the mysql_query or whatever command and print the error message (which of course is not recommended for scripts in production)?
I am not totally certain how PHP deals with processes and how consecutive queries are run, but if you want to make certain to encapsulate the delete in a transaction, you can do so with PDO like this:
$dbh->beginTransaction();
$sth = $dbh->exec("DELETE FROM `rtable` WHERE `UserName`='%s'");
$dbh->commit();
// You could also pop a transaction around the inserts
// in case another page tries to do the same
$sth = $dbh->exec("INSERT INTO `table`
(`UserName`,`Attribute`,`op`,`Value`)
VALUES ('%s','%s','%s','%s')");
BTW: I took the liberty of correcting the single quotes to backticks in your queries.
I have a php script that receives $_['post'] data from a button in flash , some times the user does double click on that button and the data sends twice , it causes mysql update conflict in server side .
How can i ignore the further requests in php from the same client in a little time diffrence?
Have you ever heard of locking tables in mysql?
It's not possible to provide detailed example without you providing more details, but basic example would be:
mysql_query( "LOCK TABLES updates READ WRITE", $connection);
$q = mysql_query("SELECT COUNT(*) FROM updates WHERE user = $currentUser AND time...");
if( mysql_result($q, 0, 0) != 0){
// Someone's already doing update; exit
mysql_query( "UNLOCK TABLES;");
return false;
}
// Require lock for ourselves
mysql_query( "INSERT INTO updates ...");
mysql_query( "UNLOCK TABLES;");
// Do the stuff on database
This makes sure that when the same user will try to do this twice he or she won't be allowed to (just one update at the time).
You have also different options:
Use TRANSACTION
Generate one time token for updating (beware of atomicity, you'd have to execute DELETE FROM ... and then check affected rows, because SELECT; DELETE my get interrupted or you'd have to use table locking again)
And my favourite one: button.enable=false, and on request completed button.enabled=true
Note: the code is vulnerable against SQL Injection and you mysql_ functions are outdated.
Why not have a last updated timestamp in the database and then check that against the current time. If it's in the last couple of seconds, then don't run the MySQL query.
You can add basic protection mechanism, as you can add a hidden random value to the form and maintain a table of displayed values, from which you delete the used ones before executing the main query. This would also prevent XSS.
I am trying to write some code that updates a mysql table, and then selects out of that same table in the same page. However, I find that when I do the update query, then the select query, it does not recognize the changes. If, however, I refresh the page, then it recognized the changes.
I first have an insert statement something like this
$query = 'INSERT INTO matches (uid, win) VALUES ($uid, $win)';
mysql_query($query) or die(mysql_error() . ' in ' . $query);
Then, just after this, I have a select statement like
$query = "SELECT * FROM matches where uid = $uid";
$resultmain = mysql_query($query) or die(mysql_error() . ' in ' . $query);
Of course I simplified the queries but, that is the general idea - and what happens is: the select statement will not recognize the update that was run immediately before it. However, if I reload the page, and the select statement runs again after some time, it does recognize the change.
I googled for this and was very surprised to not come across anything yet. Is there any good way to force to wait until the mysql update query finished before selecting? If not, I might just have to use javascript to automatically reload the page, but this sounds like a messy solution.
Any help would be greatly appreciated, this has been driving me crazy...
--Anthony
That should not happen. Maybe it’s a problem in your code, which you did not post?
Things that come to mine, which could be the problem:
The 2 queries are run on different connections to the MySQL database. And auto-commit is not enabled.
Thus, first query would send the update but not commit, the second query will query on old data, and only after the page finishes (/later on) the commit occurs.
I’m not quite sure if non-auto-commited changes will be commited or rolled back when a PHP script ends, but it should be a rollback. Thus a later commit would be needed in your code as well for this possible scenario to apply.
I'm trying to grasp the idea of transactions fully. Therefore the following question... (ofcourse newbie, so don't laugh :D )
I have set up a (simplified) transaction in PHP (using the PHP SQL driver from microsoft). I want to get the rows I'm going to delete for some extra processing later:
sqlsrv_begin_transaction($conn);
$sql = "SELECT * FROM test WITH (XLOCK) WHERE a<10";
$statement = sqlsrv_query($conn,$sql);
$sql = "DELETE FROM test WHERE a<10";
sqlsrv_query($conn,$sql);
$result = get_result_array($statement);
sqlsrv_commit($conn);
$result2 = get_result_array($statement);
1) I do get the expected result in $result but an empty array in $result2. Why?
I would expect only a result in $result2 because then the transaction has actually been executed. I guess the result in $result is a sort of 'temporary' result in memory and not actually a result from the actual database.
2) It could be that between the moment the transaction was started and the actual commit, an other query from another connection has changed the rows which match (a<10)? That means that the results I'm expecting according to $result will be different from the actual changes in the database.
Or is it that (a) the transaction occurres with an in-memory copy of the database (not affected by in-between queries from other connections), or (b) the locks obtained since the beginning of the transaction are already in action for other queries from other connections?
After typing this I'm expecting answer b....?
I'm not familiar with the sqlsrv driver, but if it works anything like most other PHP DB drivers, the result of the sqlsrv_query call is not a result set in some form of array, but a PHP resource (see http://www.php.net/manual/en/language.types.resource.php). Calling get_result_array still retrieves data from that resource, in this case the database, and it does so immediately. The COMMIT only affects writes to the database, not reads, so you see your result immediately in result1. After you commit your transaction (i.e, the DELETE), the next call correctly returns an empty result set.
I tested it out with some mysql tools (which i'm more familiar with):
1. When I start a transaction and do a 'select' of one particular record I directly get the result. Then from an other connection I delete the same record (with autocommit) it is gone for that connection but for the first connection the record is still there (I did the 'select' again without committing the transaction). Only after committing the transaction of the first connection and doing the 'select' again the record is gone.
2. When I do the same but acquire an exclusive lock for the first 'select' query then the delete query of the second connection waits until the transaction of the first connection has been committed.
Conclusion: In situation (1) for the second select query of the first connection, the database IS returning a result as it was at the moment of the start of the transaction... thus WITHOUT taking into account other (write) queries running AFTER the start of the transaction. Situation (2) is exactly the answer 2b from my original question. :)
Im wondering if the way i use to retrieve the id of the last row inserted in a postgresql table is efficent..
It works, obviously, but referencing on the serial sequence currval value could be problematic when i have many users adding rows in the same table at the same time.
My actual way is:
$pgConnection = pg_connect('host=127.0.0.1 dbname=test user=myuser password=xxxxx')or die('cant connect');
$insert = pg_query("INSERT INTO customer (name) VALUES ('blabla')");
$last_id_query = pg_query("SELECT currval('customer_id_seq')");
$last_id_results = pg_fetch_assoc($last_id_query);
print_r($last_id_results);
pg_close($pgConnection);
Well, its just a test atm.
But anyway, i can see 3 issues with this way:
Referencing on the customer_id_seq, if two user do the same thing in the same time, could happen that them both get the same id from that way... or not?
I have to know the table's sequence name. Becose pg_get_serial_sequence dont works for me (im newbie on postgresql, probably is a configuration issue)
Any suggestion/better ways?
p.s: i can't use the PDO, becose seem lack a bit with the transaction savepoint; I wont use zend and, in the end, i'll prefer to use the php pg_* functions (maybe i'll build up my classes in the end)
EDIT:
#SpliFF(thet deleted his answer): this would works better?
$pgConnection = pg_connect('host=127.0.0.1 dbname=test user=myuser password=xxxxx')or die('cant connect');
pg_query("BEGIN");
$insert = pg_query("INSERT INTO customer (name) VALUES ('blabla')");
$last_id_query = pg_query("SELECT currval('customer_id_seq')");
$last_id_results = pg_fetch_assoc($last_id_query);
print_r($last_id_results);
//do somethings with the new customer id
pg_query("COMMIT");
pg_close($pgConnection);
If you use a newer version of PostgreSQL (> 8.1) you should use the RETURNING clause of INSERT (and UPDATE) command.
OTOH if you insist on using one of the sequence manipulation functions, please read the fine manual. A pointer: "Notice that because this is returning a session-local value, it gives a predictable answer whether or not other sessions have executed nextval since the current session did."
Insert and check curval(seq) inside one transaction. Before commiting transaction you'll see curval(seq) for your query and no matter who else inserted at the same time.
Don't remember the syntax exactly - read in manual (last used pgsql about 3 years ago), but in common it looks like this:
BEGIN TRANSACTION;
INSERT ...;
SELECT curval(seq);
COMMIT;
ex. minsert into log (desc,user_id) values ('drop her mind',6) returning id