PHP Open Multiple Connections - php

I would like to run multiple scripts instances of the same script in different browser tabs. And I would like them to have different MySQL connections. Each its unique connection.
I know that mysql_connect has a fourth parameter $new_link which should open a new link, but even that does not open a new connection, usually. Sometimes it does.
I have a XAMPP install on a Widows machine.
The question is: How can I absolutely force PHP/MySQL to open a new connections for each instance of a script? Script runs for about 2mins.
http://localhost/myscript.php
Here are the excerpts of the MySQL code. First load a work assignment from DB and mark it as in progress:
public function loadRange() {
try{
$this->db()->query('START TRANSACTION');
$this->row = $this->db()->getObject("
SELECT * FROM {$this->tableRanges}
WHERE
status = " . self::STATUS_READY_FOR_WORK . "
AND domain_id = {$this->domainId}
ORDER BY sort ASC
LIMIT 1");
if(!$this->row) throw new Exception('Could not load range');
$this->db()->update($this->tableRanges, $this->row->id, array(
'thread_id' => $this->id,
'status' => self::STATUS_WORKING,
'run_name' => $this->runName,
'time_started' => time(),
));
$this->db()->query('COMMIT');
} catch(Exception $e) {
$this->db()->query('ROLLBACK');
throw new Exception($e->getMessage());
}
}
Then the script may or may not INSERT rows in another table based on what it finds.
In the end, when task is finished, the assignment row is UPDATEd again:
$this->db()->update($this->tableRanges, $this->row->id, array(
'status' => self::STATUS_EXECUTED,
'time_finished' => time(),
'count' => $count,
));
In particular, the $this->tableRanges table looks to be locked. Any idea why it is the case? It is an InnoDB table.

I would like to run multiple scripts instances of the same script in different browser tabs. And I would like them to have different MySQL connections. Each its unique connection.
This is actually the case, without any additional effort
The question is: How can I absolutely force PHP/MySQL to open a new connections for each instance of a script.
Answer: do nothing :)

every time you hit http://localhost/myscript.php a new instance is run. Everything about that instance is unique, the web server spawns a new PHP thread, in which all the resources, connections, variables are unique.
Only state management devices such as sessions are shared and that too if you are using different tabs in same browser. If you hit the same URL with different browsers, the state management resources are different too.
To answer your question, like others mentioned before - your connection is different for each instance IF you are using mysql_connect. You could create a persistent connection that does not close when the application exits and reuses it for new connection requests using mysql_pconnect. But in your code it seems you are using the latter and in that case, you are fine.
You can try to set the isolation read level to prevent table stalling while reading for select
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
More information can be found here.
Again I guess it will take a bit of playing around to find which option works the best.

Related

Alternative connection to database without PHP?

Objective: Update prices of products between databases: Shop's server DB has the latest prices and website's DB need to be updated accordingly with any "each 24 hours" script (I'll look this up later).
I'm using Ionos as hosting for the website, and The server is shared, so I can't touch php.ini or add files for php.
I'm trying to connect to a SQL server DB, but since it requires dll libraries to be installed and to modify the php.ini, I can't do that.
I can't either make it from the other side, If I make it from an external server in order to update the prices of the website, they don't allow to make connections out of the context of the server.
So, I know that the solution is to upgrade the hosting's plan and pay more and so on, so I have a virtual server for my own. But before doing that, is there any other way to establish this connection without using php? Is there something else that allows me to create a DB connection?
The fatal errors appears as soon as sqlsrv_connect is read as there is no library to load this function.
$serverName = "x, 0000";
$connectionInfo = array( "Database"=>"x", "UID"=>"x", "PWD"=>"xxx");
$conn = sqlsrv_connect( $serverName, $connectionInfo);
Edit: Comes to my mind... Maybe a solution would be to tell this php file to load php.ini and so on from another server if that's possible?
You could possibly call a JSON endpoint on your DB server (secure the endpoint though (out of scope for my answer)) https://3v4l.org/Gpi28
<?php
// MSSQL server side
$data = [
1 => 'hello',
2 => 'world',
];
// Imagine $data above is the array of rows returned by the db query
header('Content-Type: application/json');
echo json_encode($data);
exit;
// IONOS Side
$json = file_get_contents('http://your-database-server/some/url/or/other');
$data = json_decode(true);
// Now do your updates
// NB This is an INSECURE example, people who know the URL can see this data!

PHP PDO SQL - update inner join query freezes during execution

I need to run a daily PHP script that downloads a data file and executes a bunch of SQL Queries in sequence to import and optimize the data.
I'm having a problem executing one of my queries within PHP which appears to freeze the mysqld process on my server. Oddly, running the same query does not case a similar problem when run from the Sequel Pro Database client program (Mac).
The query is running an update on a large table with over a million rows. Here is the stored procedure I'm using:
DELIMITER ;;
CREATE PROCEDURE spSetTripIdInStopTimes()
BEGIN
-- SET META_TRIP_ID IN IMPORT_STOP_TIMES
UPDATE import_stop_times
INNER JOIN ref_trips ON
(
import_stop_times.trip_id = ref_trips.trip_id
AND import_stop_times.meta_agency_id =ref_trips.meta_agency_id
)
SET import_stop_times.meta_trip_id = ref_trips.meta_trip_id;
END;;
DELIMITER ;
When the procedure is called with
CALL spSetTripIdInStopTimes;
inside Sequel Pro, the result is 1241483 rows affected and the time taken is around 90 seconds.
With PHP PDO I run the same command with
$result = $database->runExecQuery("CALL spSetTripIdInStopTimes");
However, it gets stuck on this query for over 24 hrs and still has not completed. When I cancel the PHP script I can see that the mysqld process is still taking %99.5 CPU. At this point I restart SQL with 'sudo service mysql restart'.
I also tried using PHP's mysqli, but the freezing also occurs with this method.
$mysqli->query("CALL spSetTripIdInStopTimes")
Would anyone be able to reason why this is happening or suggest another method?
Thank you in advance.
Note: I also tried using the older mysql on PHP, but the version I'm using (5.5.9-1ubuntu4.14) tells me the command is deprecated and stops the script.
[UPDATE]
I've also tried running the stored procedure directly on the command line:
mysql --user=[username] --password=[password] --execute="call spSetTripIdInStopTimes()" [tablename]
which worked.
So I tried running the same command with PHP's exec() function:
exec("mysql --user=[username] --password=[password] --execute=\"call spSetTripIdInStopTimes()\" [table name]");
Unfortunately, it stills hangs. I'm starting to wonder if this is due to the limitation or overhead of PHP.
[UPDATE 2]
Here is the array of PHP PDO connection options I use:
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// Allow file reading, need following settings to import data from txt files
PDO::MYSQL_ATTR_LOCAL_INFILE => true,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
PDO::ATTR_EMULATE_PREPARES => true)
[UPDATE 3]
I'm using a custom database object, so I'll show the function for $database->runExecQuery() for clarification:
function runExecQuery($queryString)
{
$db = $this-> getConnection(); // Connect to database
try{
return array(
"success"=> true,
"data"=>$db->exec($queryString)
);
}
catch (PDOException $ex)
{
return array(
"success"=> false,
"errMessage"=> "ERROR[{$ex->getCode()}]".($this-> Debug ? "{$ex}" : "")
);
}
}
The variable $db is the connection variable that is initialized as follows:
// Create address string
$db_address =
"mysql:host={$settings['db_hostname']};".
"dbname={$settings['db_name']};".
"charset={$settings['db_charset']}";
// Create connection to database
$db = new PDO($db_address, $settings['db_user'], $settings['db_pw'], $options);
where $options is the array from [Update 2].
[Update 4]
Mihai's suggestion of changing PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false had some promising results as query appeared to finish. However, after more testing I found that the PHP script will sometimes still hang on the Query about 50% of the time it is run. This is true even with the same set of data in the SQL tables.

Why do we have to close the MySQL database after a query command?

I'm starter.
I want to know what will happen if we don't close the MySQL connection.
1- Is it possible to open more than one database if we don't close them? I mean can we open more than one database in a same time?
2- Does closing database increase the speed?
3- Is it necessary to close the database or it is optional?
Look at this code. I don't use "mysql_close()" so I don't close the database after each request. There are a lot of requests for this PHP page. Maybe 50000 per each minute. I want to know closing database is necessary for this code or no?
<?php
//Include the file that lets us to connect to the database.
include("database/connection.php");
//Call "connect" function to connect to the database.
connect("database", "localhost", "root", "", "user");
//The GPRS module send a string to this site by GET method. The GPRS user a variable named variable to send the string with.
$received_string = $_GET["variable"];
//Seprates data in an array.
$array_GPRS_data = explode(",", $received_string);
//we need to remove the first letter.
$array_GPRS_data[9] = substr($array_GPRS_data[9], 1);
$array_GPRS_data[13] = substr($array_GPRS_data[13], 4, 2).substr($array_GPRS_data[13], 2, 2).substr($array_GPRS_data[13], 0, 2);
//Query statement.
$query = "INSERT INTO $array_GPRS_data[17](signal_quality, balance, satellite_derived_time, satellite_fix_status, latitude_decimal_degrees,
latitude_hemisphere, longitude_decimal_degrees, longitude_hemisphere, speed, bearing, UTCdate, theChecksum)
VALUES('$array_GPRS_data[0]', '$array_GPRS_data[1]', '$array_GPRS_data[5]', '$array_GPRS_data[6]', '$array_GPRS_data[7]',
'$array_GPRS_data[8]', '$array_GPRS_data[9]', '$array_GPRS_data[10]', '$array_GPRS_data[11]', '$array_GPRS_data[12]', '$array_GPRS_data[13]',
'$array_GPRS_data[16]')";
//Run query.
$result = mysqli_query($query);
//Check if data are inserted in the database correctly.
if($result)
{
echo("*#01");
}
else
{
echo("Error: 001");
echo (mysqli_error());
}
?>
Yes, you can have multiple database connections. You are not opening a database, you are opening a database connection. The database is 'open' (i.e. running) all of the time, generally speaking, whether you are connected to it or not.
Depends... if you only have one open connection on a page, then you don't need to close it because it will automatically close when PHP is done. If you have many, then you could potentially make the database server slower, or make the database server run out of available connections (it can only have a certain number of connections open at the same time). That said, most modern database servers can handle hundreds of concurrent connections.
Optional, but recommended. It's not a big deal for small-medium projects (i.e. if you have less than 100 concurrent visitors at any given time, you probably won't have any issues regardless). Since you have many thousand visitors per minute, you should actively close the database connection as soon as you are done with it, to free it up as soon as possible.
Once you connect to the database it is not necessary to close. As non-persistent connection automatically closed at the end of script execution.
Follow this for more information

How can I get php pdo code to keep retrying to connect if there are too many open connections?

I have an issue, it has only cropped up now. I am on a shared web hosting plan that has a maximum of 10 concurrent database connections. The web app has dozens of queries, some pdo, some mysql_*.
Loading one page in particular peaks at 5-6 concurrent connections meaning it takes a minimum of 2 users loading it at the same time to spit an error on one or both of them.
I know this is inefficient, I'm sure I can cut that down quite a bit, but that's what my idea is at the moment is to move the pdo code into a function and just pass in a query string and an array of variables, then have it return an array (partly to tidy my code).
THE ACTUAL QUESTION:
How can I get this function to continue to retry until it manages to execute, and hold up the script that called it (and any script that might have called that one) until it manages to execute and return it's data? I don't want things executing out of order, I am happy with code being delayed for a second or so during peak times
Since someone will ask for code, here's what I do at the moment. I have this in a file on it's own so I have a central place to change connection parameters. the if statement is merely to remove the need to continuously change the parameters when I switch from my test server to the liver server
$dbtype = "mysql";
$server_addr = $_SERVER['SERVER_ADDR'];
if ($server_addr == '192.168.1.10') {
$dbhost = "localhost";
} else {
$dbhost = "xxxxx.xxxxx.xxxxx.co.nz";
}
$dbname = "mydatabase";
$dbuser = "user";
$dbpass = "supersecretpassword";
I 'include' that file at the top of a function
include 'db_connection_params.php';
$pdo_conn = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
then run commands like this all on the one connection
$sql = "select * from tbl_sub_cargo_cap where sub_model_sk = ?";
$capq = $pdo_conn->prepare($sql);
$capq->execute(array($sk_to_load));
while ($caprow = $capq->fetch(PDO::FETCH_ASSOC)) {
//stuff
}
You shouldn't need 5-6 concurrent connections for a single page, each page should only really ever use 1 connection. I'd try to re-architect whatever part of your application is causing multiple connections on a single page.
However, you should be able to catch a PDOException when the connection fails (documentation on connection management), and then retry some number of times.
A quick example,
<?php
$retries = 3;
while ($retries > 0)
{
try
{
$dbh = new PDO("mysql:host=localhost;dbname=blahblah", $user, $pass);
// Do query, etc.
$retries = 0;
}
catch (PDOException $e)
{
// Should probably check $e is a connection error, could be a query error!
echo "Something went wrong, retrying...";
$retries--;
usleep(500); // Wait 0.5s between retries.
}
}
10 concurrent connections is A LOT. It can serve 10-15 online users easily.
Heavy efforts needed to exhaust them.
So there is something wrong with your code.
There are 2 main reasons for it:
slow queries take too much time and thus serving one hit uses one mysql connection for too long.
multiple connections opened from every script.
The former one have to be investigated but for the latter one it's simple:
Do not mix myqsl_ and PDO in one script: you are opening 2 connections at a time.
When using PDO, open connection only once and then use it throughout your code.
Reducing the number of connections in one script is the only way to go.
If you have multiple instances of PDO class in your code, you will need to add that timeout handling code you want to every call. So, heavy code rewriting required anyway.
Replace these new instances with global $pdo; instead. It will take the same amount of time but it will be permanent solution, not temporary patch as you want it.
Please be sensible.
PHP automatically closes all the connections st the end of the script, you don't have to care about closing them manually.
Having only one connection throughout one script is a common practice. It is used by ALL the developers around the world. You can use it without any doubts. Just use it.
If you have transaction and want to log something in database you sometimes need 2 connections in one script

Best approach to see if a MySQL Server is up and running

I have a Master - Slave setup for a web application written in PHP. I have a pool of slaves I use for reading, and a Master that is used for writes (and reads if a write has been sent this request). I would like to incorporate an automated system for removed crashed servers from the read pool. Currently I am using:
foreach($readers as $reader)
{
$fp = #fsockopen($reader['host'],3306,$errno,$errstr,1);
if(!$fp)
{
//Remove from pool
}
unset($fp);
}
My primary question is there a more reliable method. I have had quite a few false positives, and vice versa because it is not actually checking for a MySQL server, but rather just a connection on port 3306. Is there a way to check for a MySQL server without raising an exception, which is the behaviour of the PDO and MySQLi extensions in PHP.
You could just use mysql_connect() and check the result for false, and close the connection right away on success. You can make a dummy account with no privileges for that if you like.
That's really the only reliable way, especially if you want to distinguish a running MySQL server from any other random process listening on port 3306.
You could use mysql_ping() to check if a current DB Connection you have open is still alive
Here is the example posted at http://www.php.net/manual/en/function.mysql-ping.php
<?php
set_time_limit(0);
$conn = mysql_connect('localhost', 'mysqluser', 'mypass');
$db = mysql_select_db('mydb');
/* Assuming this query will take a long time */
$result = mysql_query($sql);
if (!$result) {
echo 'Query #1 failed, exiting.';
exit;
}
/* Make sure the connection is still alive, if not, try to reconnect */
if (!mysql_ping($conn)) {
echo 'Lost connection, exiting after query #1';
exit;
}
mysql_free_result($result);
/* So the connection is still alive, let's run another query */
$result2 = mysql_query($sql2);
?>
The best way to check if any service is alive is to actually use it. So for MySQL try to connect and execute some fast query, for web server try to fetch some file, for PHP try to fetch some simple script...
For MySQL master/slave setup, one of the solutions is to actually check the state of replication. You can check how many transactions is the slave behind master and decide to stop using that slave when/while it has old data. (I don't do the replication myself, but I think you need to compare the variables Read_Master_Log_Pos and Relay_Log_Pos)

Categories