I have just discovered PDO and I'm very excited about it, but I have read a few tutorials on how to implement it, and they show me different ways of doing it.
So now I'm confused which way is the best.
example 1: open database once.
include("host.php"); //including the database connection
//random PDO mysql stuff here
Example 2: open close the database when needed:
try {
$dbh = new PDO(mysql stuff);
$sql = "mysql stuff";
foreach ($dbh->query($sql) as $row)
{
echo $row['something'];
}
/*** close the database connection ***/
$dbh = null;
}
catch(PDOException $e)
{
echo $e->getMessage();
}
Which is best? I would think example 2 is best, but there much more code than example 1.
Usually, there is significant time spent/lost when connecting, and you want to do it only once. Do not go closing a connection you need later on, it will only slow things down. You may consider closing a connection sooner if you are reaching the maximum connections limit, but that's more a hint you should scale up then a permanent solution IMHO.
Related
I received max_user_connections error this days. and I was wondering if I am doing something wrong.
I have a config.php file with mysqli connection script:
$mysqli = new mysqli('localhost', 'my_user', 'my_password', 'my_db');
so pages where I need to get something in mysqli I include config.php. here is an example:
example.php
<?php
include_once("config.php");
$stmt = $mysqli->prepare("select...");
$stmt->execute();
$stmt->bind_result(...,...);
while($stmt->fetch()) {
...
}
$stmt->close();
?>
some html <p> <img>...
<?php
$stmt = $mysqli->prepare("select...");
$stmt->execute();
$stmt->bind_result(...,...);
while($stmt->fetch()) {
...
}
$stmt->close();
?>
some html <p> <img>...
<?php
$stmt = $mysqli->prepare("select...");
$stmt->execute();
$stmt->bind_result(...,...);
while($stmt->fetch()) {
...
}
$stmt->close();
?>
So, my question is: is it the best practise to do selects like this? should I close mysqli connect after each select and open again? or do selects on the top together without separete than with some html in the middle?
the best practise to do selects like this?
I hate it when people use the term "best practice" it's usually a good indicator they don't know what they are talking about.
The advantage of your approach is that its nice and simple. But as you've discovered, it does not scale well.
In practice its quite hard to measure, but in most applications the MySQL connection is unused for most of the lifecycle of the script. Hence there are usually big wins to be made by delaying the opening of connection and closing it as soon as possible.
The former can be done by decorating the mysqli class, the connect method just stores the credentials while anything which needs to talk to the database should call the wrapped connect method when it needs access to the database. However typically the yeild of this approach is low unless your code creates a lot of database connections which are never used (in which case a cheaper solution would be to increase the connection limit).
It can take a long time after the last query is run before the connection is closed down. Explicitly closing the connection addresses this, but requires a lot of code changes.
do not open and close a connection for each query. Although it will result in a reduced number of connections to the databasee, the performance will suck
The biggest win usually comes from optimizing your queries - reduced concurrency and a better user experience.
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
I've made this a lot of times but now I can't :(
The insert allways return false but if I execute the same SQL script (taked from the output) it inserts in the database without any problem. I'm connected to the database because some values are fetched from another table.
This is my code:
$query = "INSERT INTO normotensiones(fecha,macropera,pozo,equipo_pmx,equipo_compania,paciente,sexo,edad,id_compania,otra_compania,puesto,ta,tum,ove,coordinador)
VALUES('$fecha','$macropera','$pozo','$equipo_pmx','$equipo_compania','$paciente','$sexo',$edad,$id_compania,'$otra_compania','$puesto','$ta','$tum','$ove','$coordinador')";
if (mysql_query($query,$connection)){
//OK
} else {
$errno = mysql_errno();
$error = mysql_error();
mysql_close($connection);
die("<br />$errno - $error<br /><br />$query");
exit;
}
The output is:
0 -
INSERT INTO normotensiones(fecha,macropera,pozo,equipo_pmx, equipo_compania,paciente,sexo,edad,id_compania, otra_compania,puesto,ta,tum,ove,coordinador)
VALUES('20111001','P. ALEMAN 1739','P. ALEMAN 1715','726', 'WDI 838','SERGIO AYALA','M',33,21, '','','110/70','ROBERTO ELIEL CAMARILLO','VICTOR HUGO RAMIREZ','LIC. PABLO GARCES')
Looks like there are no error, but allways execute the code in the else part of the if instruction. Any idea? Thanks in advance.
I think the issue might be you are missing the mysql_select_db line after the connection.
After the connection with the database is established you need to select a DB. Please make sure you have selected the Database that your desired table resides in.
And you can even use the following snippets to get some useful informated through mysql_errors.
$connection = mysql_connect('localhost', 'root', 'password');
if (!$connection) {
die('<br>Could not connect: ' . mysql_error());
}
if (!mysql_select_db('db_name')) {
die('Could not select database: ' . mysql_error());
}
And try you insert query after these lines of code. All the best.
I agree with the others concerning the column types. INT is one of the only data types that do not require single quotes.
There are two blank strings. There is a possibility that the variables are not defined, and therefore giving you a PHP exception (not even in the MySql yet) but that requires stricter-than-normal exception settings. I would personally look into the $connection variable. Before the SQL query statement, put this and send us the cleaned results:
echo '<pre>'.var_dump($connection, true).'</pre>';
Additionally, on your mysql_connect function call, put
OR die('No connection')
afterwords. Do the same thing with the mysql_select_db function, changing it to 'No DB Select' obviously.
Ultimately, we will need more information. But changing to mysqli is very desirable.
Oh! And make sure the permissions for the user you are connecting as are not changed. Sometimes I find people who connect to PhpMyAdmin using one user account but a different account in their PHP code. This is problematic, and will lead to problems eventually, as you forget the different accounts, at times.
In this code I think maybe it would be best to close after both the if and else but it seems off to close it twice.
<?php
$member_id = "";
require("connect.php");
if (isset($_POST['member_id']))$member_id = fix_string($_POST['member_id']);
$sql=("DELETE FROM members WHERE member_id = '$member_id'");
$res = mysqli_query($con, $sql);
if (mysqli_affected_rows($con) == 1) {
echo "member with ID of ".$member_id." has been removed from members table";
} else {
echo "member was not deleted";
}
function fix_string($string) {
if (get_magic_quotes_gpc()) $string = stripslashes($string);
return htmlentities ($string);
}
?>
It is very common practice to open the db connection at the beginning, and close your connection once at the end. You don't need to do it in the middle of your code.
Closing database connections isn't absolutely required, as seen in the PHP manual page for mysql_close(), but it is considered good practice by many to do so.
There is a rare exception to this. If your program is going to be doing some heavy processing for several minutes, you might want to close the db connection before this. If you need it again after the processing, open the db connection again. The reason for this is that the MySQL connection will eventually time out, and then it may lead to more problems in your program.
Using mysql_close() isn't usually necessary, as non-persistent open links are automatically closed at the end of the script's execution.
Straigh out from the php manual.
Everyth worked fine, it just decided to stop working and it ruined my whole project and Im at standstill.
This is error:
mysql_close(): 5 is not a valid MySQL-Link resource in
C:\wamp\www\Includes\footer.php on line 4
This is footer.php
<?php
//close connection
if (isset($dbh)); {
mysql_close($dbh);
}
?>
This is connect.php
//set constants
require("quick.php");
//database connection
$dbh = mysql_connect(DB_SERVER, DB_USER, DB_PASS);
if (!$dbh) { //check connection
die("Cannot conect! to database ");
}
//selecting database
$db_select = mysql_select_db(DB_NAME, $dbh);
if (!$db_select) { //check connection
die("Cannot connect to database ");
}
?>
Basically whenever I try to quit mysql this error shows.
And it all worked fine not long ago.
Try this instead:
if (isset($dbh) && is_resource($dbh)) {
mysql_close($dbh);
} else {
mysql_close();
}
From manual:
mysql_close() closes the non-persistent connection to the MySQL server
that's associated with the specified link identifier. If
link_identifier isn't specified, the last opened link is used.
Maybe he's having few connections.. Who knows..
Somewhere, within your page, there is an assignment that puts $dbh = 5; that overrides your database connection. That is the cause for the error. Search for any assignments to that variable between your database opening and your footer, and you've found your problem.
Note: I wouldn't be that worried about the connection being open as some other commenters here, since if it's not a persistant connection, it will anyway be closed at the end of the script, so I don't see how that would be ruining your whole project. Your code tries to close it at the footer which is not much different than letting it close itself. From the manual:
Using mysql_close() isn't usually necessary, as non-persistent open
links are automatically closed at the end of the script's execution.
See also freeing resources.
All the mysql_* functions will assume "the last connection you opened" if you don't specify a connection. This is useful because you don't have to keep track of it like you do for other libraries. Most likely here you are overwriting the variable $dbh somewhere. Personally I'd use a variable like $_connection if I use one at all.
So just mysql_close() will be enough to close the connection. You need only worry about this kind of thing if you are handling more than one connection at a time.