This question already has answers here:
Fully Understanding PDO ATTR_PERSISTENT
(4 answers)
Closed 6 years ago.
I have the following code and freshed this webpage in Firefox for 5 times, then the MySQL showed me 5 connections. According to the PDO Manual,
Persistent connections are not closed
at the end of the script, but are
cached and re-used when another script
requests a connection using the same
credentials. The persistent connection
cache allows you to avoid the overhead
of establishing a new connection every
time a script needs to talk to a
database, resulting in a faster web
application.
I have used the same credentials, but the number of MYSQL connection keep increasing. Even trying to close connection with $db = null could not close the connections.
What's wrong of my code?
<?php
try {
$dbh = new PDO('mysql:host=127.0.0.1;dbname=lingtong', 'root', 'xxxxxx', array(PDO::ATTR_PERSISTENT => true));
foreach ($dbh->query('SELECT * from agent') as $row)
print_r($row);
$dbh = null;
} catch (PDOException $e) {
print "Error! : " . $e->getMessage() . "<br/>";
die();
}
This question is very old but it will be okay if I contribute. I think you need to implement a singleton class for handling database connections I will write a sample class below ..
<?php
class DB{
//set the connection property to private to prevent direct access
private static $conn;
//now since we dont want to reinstiate the class anytime we need it, lets also set the constructor to private
private function __construct(){}
//now lets create our method for connecting to the database
public static function connect(){
//now lets check if a connection exists already in our $conn property, then we should return it instead of recreating a new connection
if(!empty(self::$conn)){
return self::$conn;
}//end if
//upon reaching here means the $conn property is empty so lets create a new connection
try {
$dbh = new PDO('mysql:host=127.0.0.1;dbname=lingtong', 'root', 'xxxxxx', array(PDO::ATTR_PERSISTENT => true));
//lets now assign the database connection to our $conn property
self::$conn = $dbh;
//return the connection
return $dbh;
} catch (PDOException $e) {
print "Error! : " . $e->getMessage() . "<br/>";
die();
}
}//end method
}//end class
?>
Our singleton class can make only one connection and reuse it,let see how we can use our class
<?php
$dbh = DB::connect();
foreach ($dbh->query('SELECT * from agent') as $row){
print_r($row);
}
?>
It seems you need to close the cursor and release (assign null) to the last pdo statement object as well to close the connection.
Also, what's important to understand about persistent connections is that they persist, but you are not guaranteed that you will neither:
Be given back your last connection handler in further script executions
Nor be reusing a previous connection, if it's still "busy". Busy may mean in a script, timing out etc... Connections instanciation may go on and on... See Fully Understanding PDO ATTR_PERSISTENT
From what I know from persistent connection you probably doesn't need it:
you are on localhost so the connection is very fast and you wont save a lot from caching of your connection
because of the underlying principal of Apache you have many thread that answer the client request and because of these multi-threading the connection is persistent in a single thread, not shared on all of them so you will see your number of connection go up in mysql until it's reach the ThreadLimit of apache
there is a few risk that persistent connection cause problem to your app in the kind of dbLock or tableLock
Now you might wanna do a bit more research about persistent connections if you still think that you really need it
Related
i'm using Slim framework to provide an API to our clients. I'm focused on Java so that could the the point, because the problem is related with database connection.
Every request connect to the database throw PDO like
$dbh = new PDO($param1, $param2, $param3);//php 7.1
So as php don't have a connection pool i understand each request (maybe at the same time) starts a new connection throw the database.
But i'm experimenting a kind of situation here.
If one request starts a transaction for inserting or updating something, next requests will wait until this transaction finish, but it is on a different thread, so i'm thinking on table locks? or something like each request is getting the same connection.
THE PROBLEM:
So if they are in different threads with a different connection how
they need to wait until transaction ends for the first request.
My database source class is something like
class DataBaseConfig {
public static function getConn()
{
$dbh = new PDO($param1, $param2, $param3);
$dbh->exec("set names utf8");
return $dbh;
}
}
And i use it like
$db = DataBaseConfig::getConn();
$db->beginTransaction();
//code
$db->commit();
I'm missing something sure, so can someone help me with this problem?
Thanks!
NEWS! EDIT
#YourCommonSense thank you it was finally a session configuration. I
didn't know that php start_session(); locks the session file so that's
what was happening. Thanks a lot!
link: https://ma.ttias.be/php-session-locking-prevent-sessions-blocking-in-requests/
Pre-emptive apology: This post contains basic questions.However, I have searched and I have not found an answer, if there is one...sorry.
I am following some youtube tutorials for making a basic ajax web chat, and in the tutorial the person is using MySQLi to connect to the DB. I want to create the same ajax chat application except I want to use PDO instead of MySQLi.
The person uses these two files:
config.php
<?php
define('DB_HOST', 'localhost');
define('DB_USER', 'bucky_chat');
define('DB_PASSWORD', '123456');
define('DB_NAME', 'bucky_chat');
?>`
chat.class.php
<?php
require_once('config.php');
require_once('error_handler.php');
class Chat {
private $mysqli;
//constructor opens DB connection
function __construct(){
$this->mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
}
//destructor closes db connection
function __destruct(){
$this->mysqli->close();
}
}
?>
I'm trying to replicate the above snippets with PDO. The problem is that I'm not sure how to adapt the PDO examples I have looked at to do this.
First of all I'm confused as to why he defined these things in a separate file.. are there any benefits in doing this?
In another PDO tutorial I am looking at I see it can be done the followings way:
<?php
$config['db'] = array(
'host' => 'localhost',
'username' => '',
'password' => '',
'dbname' => ''
);
$db = new PDO('mysql:host=' . $config['db']['host'] . ';dbname=' . $config['db']['db_name'], $config['db']['username'], $config['db']['password']);
//some code
$db = null; //closes connection
?>
`
I think this is what I need to use (in a try catch block), but why does he put these things in an array? it seems to over complicate things... why not just variables? But does this code replicate the mysqli example? Howcome I don't see __construct() being used with PDO?
Some minor questions...
When creating a website with a user, is there a standard place to store DB connection?
Any book recommendations?
Sorry for all these questions, All help is strongly appreciated!
To answer your questions:
First of all I'm confused as to why he defined these things in a separate file
The authentication details are defined in a second file because if you create another query script, now both scripts can include the authentication details. If the authentication details change, you only need to update one file. If you are just writing a simple application, than just keep everything in one file.
but why does he put these things in an array
I think this is just done in-case the authentication details are needed someone else in the script (much like the defined globals from your first sample). Its often best practice to define parameters into variables (even if you use the variable once). This way, if you typo a variable, you will get an error; versus copy and pasting the same string over and over again.
Howcome I don't see __construct() being used with PDO
When ever you create a new object in PHP, you do not need to call __construct, it is called automatically with the "new" statement.
$PDOConnection = new PDO($dsn, $username, $password);
When creating a website with a user, is there a standard place to store DB connection
Definitely make sure the authentication details are stored in an inaccessible file to the public. The connection object has no harm to be accessed by the public (unless of course you need to authenticate the client (website user) before establishing a database connection). Is is best practice to always begin your (secure) PHP files with:
<?php
BUT... never end the file with "?>". If an extra character is inserted after the "?>" on accident, your web server could display your whole script to the world (of course your Apache, etc... would have to be configured wrong). Like I said... best practices.
Any book recommendations?
Googleing "php arcitechture best practices" may help.
You are confusing WAY TOO MUCH things that can be explained in one answer. you don't even know what to ask.
Please, don't take the art of programming as a some sort of cheap trick one can learn in 2 hours. To write a AJAX-based chat one need to learn for at least several months. To learn by understanding, not by copy-pasting. To learn step by step, going from variables to arrays, from arrays to functions, from functions to classes and so on - not by throwing all the code they find in one bowl and then asking on SO how to deal with all that. One cannot get to another step without having understand a previous one. And of course all these youtube tutorials are definitive pieces of useless rubbish.
some of your confusions are:
__construct() method actually has nothing to do with PDO. Nor with mysql. this is a Chat class method. And method which is all wrong. Chat class shouldn't create its own connection but use already created one.
This thing on variables vs. array vs. constants doesn't really matter. To have connection options in a separate file is a good thing but nonetheless you need to have a connection code in the separate file as well, to avoid writing connection code in the every file.
You should not use this code in a try catch block (unless you have an idea what to do in case of error, which I doubt you have).
Before starting for a chat, you have to learn smaller, simpler applications, like telephone book or the like, to learn basic database operations, from which you'll be later able to build ANY application, like any house can be built of bricks.
PDO basics you can get right here, in the tag wiki. But OOP basics is not that easy.
First the reason you define config in different file is so that you can just include that file instead of writing the database configuration anytime you want database access. It is preferred best practice.
you can do:
try
{
$PDOConnection = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.'', DB_USER, DB_PASS);
$PDOConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Do you stuffs
$PDOConnection = null;
}
catch(PDOException $e)
{
//Do something with error
}
Why not just do:
<?php
$hostname = 'host';
$dbname = 'dbname';
$username = 'uname';
$password = 'pw';
try {
$db = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $ex) {
echo "An Error occurred!";
}
?>
In a separate PHP file I call mine dbPDO.php and then have:
require_once("dbPDO.php");
In your PHP pages. And then run queries by doing:
EDIT: to condense my answer.
$username = $_POST['username'];
$stmt = $db->prepare("SELECT field1, field2, field3, etc FROM mytable WHERE username = :username");
$stmt->bindParam(':username', $username);
$stmt->execute();
while ($r = $stmt->fetch()) {
$field1 = $r['field1'];
$etc = $r['etc'];
}
Make sure you bindParam and use the ':' in the query. Don't just put WHERE username = $username or WHERE username = $_POST['username'] That would led you prone to SQL Injection. Also, I didn't show it here, but you should have some sort of exemption handling for each query. I place the whole query in a Try/Catch, but I hear there are other ways to deal with it. I personally think its personal preference.
First of all you don't need an array nor variables, you can directly input the configuration..like:
try { //try connection
//common db
$db = new PDO('mysql:host=localhost;dbname=some_db_name', 'some_usernane', 'some_pass');
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $e) { //connection failed
die("Oh no! It seems we took too long to respond, we are sorry for that..");
}
Secondly _constructor() means that whenever the class Chat is called everything in the _constructor() is executed .
Here is a good tutorial for PDO http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
I am used to mysql database access using the procedural mysql method. I am a beginner - intermediate programmer.
I am trying to learn the PDO api, however all resources which discuss using PDO show the connection string, username and password.
e.g.
<?php
try {
$db_conn = new PDO('mysql:host=localhost;dbname=databaseName','username', 'password');
}
catch (PDOException $e) {
echo 'Could not connect to database';
}
$sql = 'SELECT * FROM Products';
$stmt = $db_conn->prepare($sql);
...
...
...
?>
What I want, and think would be better programming is to put my PDO connection into a new file. then where I want to run an SQL query, I require_once('PDO.php') or similar.
The problem I have with this is as follows:
How do I close the connection? Simply $db_conn = null; ??
Should I close the connection after each query is run, then re-open the connection?
Should I close the connection or is it automatically destroyed when the user closes the browser?
I am working from a book called PHP Master: Writing Cutting Edge Code. http://www.sitepoint.com/books/phppro1/ and this has completely omitted any reference to closing the connection / destroying the object after it has been used.
Furthermore, I have looked at online tutorials, and they all connect to the database using PDO inline as opposed to having a separate database connector. This I am not happy with for many reasons:
I have to type username & password to connect every time.
If I get a developer to take a look at code / write some code, they will all have access to the database.
If I change the DB username & Password, then each file which connects to the database will need to be updated.
Could anybody recommend a better resource? Could anybody advise on what is the best practice way to do this?
Many thanks
Your question about how to store the database name, username and password have nothing to do with the capabilities of PDO. This is an implementation choice. The way you use to work with procedural functions can also be applied to PDO, the difference is that with PDO you work with objects instead.
So for simplicity, store the PDO creation of an object, either in a function or class, in which you can create the PDO instance anytime, e.g.
function createPDO($cfg) {
try {
return new PDO("mysql:host=".$cfg['host'].",port:".($cfg['port']).";dbname=".($cfg['name']).";",$cfg['username'], $cfg['password']);
} catch(PDOException $e) {
// handle exceptions accordingly
}
}
You can centralise these in whatever PHP file you like to include, just like you were used with the procedural functions.
You have two choices, either put all the relevant database information inside the createPDO, or use something like a config ($cfg) variable to store all this information.
$config = array();
$config['db'] = array(
'host' => 'localhost',
'name' => 'databse',
'username' => 'userx',
'password' => 'passy'
/* .. etc */
)
Using the createPDO function would be as followed
$db_conn = createPDO($config['db']);
For connections closing, each connection made to the database automatically disconnects after PHP exits its execution. You can however, close the connection if you wish, by setting the variable of the PDO object you assigned it to, in this example (and in yours) $db_conn to null
$db_conn = null; // connection closed.
The PDO has a manual http://php.net/manual/en/book.pdo.php here, which is a good start getting to know PDO a bit better.
You do not close the connection after a query, you simply leave it open for the next query. When PHP exists and your page is shown, the connection will be closed automatic.
It is a good idea to put the db stuff in a separate file and include that.
Even better, put all your db stuff in a class in use that.
Have a look at the pdo php page. Although not the best examples, they should get you started.
My question is I am using the variable $db in my general script code and within one of my functions. It's purpose is to be the variable that is used for MySQL connections. I have a need inside a function to write some data to the database. In my script I cannot assume that an existing db connection will be open so I open a new one and close it before the function exits. Ever since doing this I am getting an error after the script runs saying the MySQL reference is bad / doesn't exist.
The only thing I can pin it to is in my core code I use the variable $db as the variable name for database connection. I also use the same variable in the function. I did not imagine this would be a problem because I do not use global in front of $db in the function. This should mean the $db I reference in my function is in the functions private scope but it seems to be closing the public $db's connection.
Any thoughts?
Fragments of my code are:
database.php
db_connect()
{
// open mysql db connection and return it;
}
db_close( &$db )
{
// close the passed by reference db connection
}
api.php
api_verify( $keyid, $userid, $key )
{
// open a new db connection
$db = db_connect();
// check for errors. if any errors are found note them in the db
// close the db
db_close($db);
}
main.php
include api.php;
include database.php;
// open a connection to the db
$db = db_connect();
// pull a list of things to process from the db and move through them one at a time
// call api_verify() on each key before working through it's data.
db_close($db)
To manage DB connections, you can create a class rather than a pair of functions. If where you say "MySQL reference", the exact error refers to a "MySQL resource", then you are using the outdated mysql extension and should switch to a more modern extension, such as PDO.
class DBConnection {
protected static $_connections = array(),
static connect($dsn) {
if (!isset(self::$_connections[$dsn])) {
$credentials = self::getCredentials();
/* Create connection. For example: */
try {
self::$_connections[$dsn][0] = new PDO($dsn, $credentials['username'], $credentials['password']);
} catch (PDOException $exc) {
// erase the frame w/ password from call trace to prevent leak.
throw new PDOException($exc->getMessage(), $exc->getCode());
}
/* End create connection example */
self::$_connections[$dsn][0]->dsn = $dsn;
}
++self::$_connections[$dsn]['count'];
return self::$_connections[$dsn][0];
}
static close($db) {
if (isset(self::$_connections[$db->dsn])) {
if (--(self::$_connections[$db->dsn]['count']) < 1) {
unset(self::$_connections[$db->dsn]);
}
}
}
static getCredentials() {
/* credentials can be stored in configuration file or script, in this method, or some other approach of your own devising */
}
}
Note that this isn't exactly OOP (it is, but only in a technical sense). The above doesn't lend itself well to unit testing. If you want a more OO approach (which will be more amenable to unit testing), extend or wrap PDO. Using dependency injection can also help with the coupling issues of the above.
I assume you are opening a connection to the same database with the same username/password at each of the places you call db_connect. When doing so,unless your db_connect explicitly specifies, that you are creating a new link, it will return an already opened link.If that link is then closed using db_close(), it will also close the other connection, since the link is the same. If you are using mysql_connect to connect to the database, it takes an argument called new link
new_link
If a second call is made to mysql_connect() with the same arguments, no new link will be established, but instead, the link identifier of the already opened link will be returned. The new_link parameter modifies this behavior and makes mysql_connect() always open a new link, even if mysql_connect() was called before with the same parameters. In SQL safe mode, this parameter is ignored.
Refer to http://php.net/manual/en/function.mysql-connect.php
I'm not sure if this is the issue you are facing. Hope it helps.
I would assume what is happening is the connect cancels out because there already is a connection, and then the close ends the current connection.
I would recommend either A) start a connection at the beginning of the file, and just know it's always there (what I do); or B) check the to see if the $db variable is set, if not then create the connection, and always end the connection at the end of the file.
I have a script that connects to multiple databases (Oracle, MySQL and MSSQL), each database connection might not be used each time the script runs but all could be used in a single script execution. My question is, "Is it better to connect to all the databases once in the beginning of the script even though all the connections might not be used. Or is it better to connect to them as needed, the only catch is that I would need to have the connection call in a loop (so the database connection would be new for X amount of times in the loop).
Yeah Example Code #1:
// Connections at the beginning of the script
$dbh_oracle = connect2db();
$dbh_mysql = connect2db();
$dbh_mssql = connect2db();
for ($i=1; $i<=5; $i++) {
// NOTE: might not use all the connections
$rs = queryDb($query,$dbh_*); // $dbh can be any of the 3 connections
}
Yeah Example Code #2:
// Connections in the loop
for ($i=1; $i<=5; $i++) {
// NOTE: Would use all the connections but connecting multiple times
$dbh_oracle = connect2db();
$dbh_mysql = connect2db();
$dbh_mssql = connect2db();
$rs_oracle = queryDb($query,$dbh_oracle);
$rs_mysql = queryDb($query,$dbh_mysql);
$rs_mssql = queryDb($query,$dbh_mssql);
}
now I know you could use a persistent connection but would that be one connection open for each database in the loop as well? Like mysql_pconnect(), mssql_pconnect() and adodb for Oracle persistent connection method. I know that persistent connection can also be resource hogs and as I'm looking for best performance/practice.
Here is a good post on why persistent connections could cause problems
Use a lazy connection wrapper class:
class Connection
{
private $pdo;
private $dsn;
public __construct($dsn)
{
$this->dsn = $dsn;
}
public query($sql)
{
//the connection will get established here if it hasn't been already
if (is_null($this->pdo))
$this->pdo = new PDO($this->dsn);
//use pdo to do a query here
}
}
I hope you're already using PDO. If not, you should be. PDO is database independent. If you did this using procedural functions, you'd have to create a new class for each database type.
Anyways, this is just a skeleton (you'd want to add a $params option in query(), for example), but you should be able to get the idea. The connection is only attempted when you call query(). Constructing the object does not make a connection.
As an aside, consider using Doctrine. It has lazy connections and makes life easier in general.
The best performance/practice rule is simple: do connect to one database only.
As for the connects - try to implement some database access class. Which can connect automatically on demand.