I have a database class that I developed. But I have doubts about performance in case of load. There are two issues that I was curious about and couldn't find the answer even though I searched.
When the database connection is bound to a static variable in the class,
class DB
{
static $connect;
......
function __construct()
{
try {
self::$connect = new PDO("{$this->db_database}:host={$this->db_host};dbname={$this->db_name};charset=utf8mb4", "{$this->db_username}", "{$this->db_password}");
self::$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$connect->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES utf8mb4");
} catch ( PDOException $e ){
echo '<b>ERROR: </b>'.$e->getMessage();
exit;
}
}
}
PDO::ATTR_PERSISTENT => true
Does it have an equivalent ability?
Also, I didn't fully understand the pdo permalink logic, it uses the existing connection instead of opening a separate connection for each user. But how does he use the existing link here? For example "ip address" etc.
Thank you for your help.
Let me approach the issues from a different direction.
A program should have only one connection to the database. (There are rare exceptions.) Your code, as it stands, seems to be inconsistent. It has a single ("static") connection, yet the class can be instantiated multiple times, thereby connecting multiple times. (I don't want to depend on anything "persist" to clean up the inconsistency.)
Either make the class a singleton or otherwise avoid being able to call __construct a second time. One approach goes something like this:
class DB {
private static $connect;
......
public function __construct() {
if (! self::$connect) {
self::$connect = ...
}
}
public function Fetch(...) {
self::$connect->...
return ...;
}
$con = new DB();
$data = $con->Fetch(...);
(plus suitable try/catch)
Note that that allows you to sub-class as needed.
Another approach might involve preventing the use of new:
private function __construct() { ... }
plus having some public method invoke that constructor.
Here's another approach. It can be used on an existing class that you don't want to (or can't) modify:
function GetConnection() {
static $db;
if (! $db) {
$db = new ...;
}
return $db;
}
$db = GetConnection();
$db->Fetch(...)'
As for "connection pooling", it is of limited use with MySQL. (Other products need it much more than MySQL does.) In my opinion, don't worry about such.
Do not use "auto-reconnect". If the connection dies in the middle of a transaction and is automatically restarted, then the first part of the transaction will be rolled back while the rest might get committed. That is likely to lead to data inconsistency.
Singletons, statics, globals, void*, critical sections all make me cringe. When I need such, I rush to find a way to "hide" it, even if that means writing cryptic code in some class(es).
For performance, MySQL really needs a single connection throughout the program. I compromise by hiding the connection in a "static" that serves at a "global". Then I hide that inside the class that I use to abstract the object(s).
I agree with Karwin's [now delete] Answer -- that this discussion is "much ado about nothing". MySQL performance is mostly about indexing, query formulation, and even the architecture of the application. Not about connections, common code elimination, redundant function calls, etc.
Related
I've ran into an issue with user already has more than 'max_user_connections' active connections
This happens because I use functions for the website functionality, each function contains a
$mysqli = connect();
Though at the same time, each function closes the mysqli at the end of function
mysqli_close($mysqli);
I do not want to include $mysqli as a parameter of the function, as the function is dynamic and would be tiresome to include it with each function call.
the connect() function just contains:
$mysqli = new mysqli(...);
return $mysqli;
I believe the error is thrown because the function sometimes calls itself for different executions, based on user input and pre-requisites... even though the mysqli is closed at the end of the function...
I'd like to know if there is a way of re-using a $mysqli connection sort of like in a global way...
I'm not sure whether I've explained myself fully so if you need some more information please leave a comment.
The proper way to reuse the same object across multiple functions/classes is to use dependency injection. Together with DI container, it can take care of providing the necessary dependencies to your functions leaving them clean.
The principle of clean code demands that your functions do not have side effects and they only do what their name states. This means that you should never be using globals in your functions as that would be causing side effects. The proper way to provide data without side effects to your function is via parameters. A connection to the database is the data that is required by your function.
If your code will be used as some kind of public library, it's even more reason to keep it clean. A function cannot have surprising behaviour. The best way to reduce surprises is by having a clear function signature. This means that all dependencies are listed as parameters with their correct types, the function cannot take dynamic arguments, and the return type must be clearly specified.
When it comes to mysqli connections (or PDO for that matter which you should prefer over mysqli), the connection should only be opened once during the execution of the script. You should never need to close the connection manually.
Here's an example of clean code. Let's imagine that you need to save bookings in the database. You create a service in your model:
<?php
class BookingService
{
public function __construct(protected mysqli $mysqli)
{
}
public function saveBooking(Booking $booking)
{
$stmt = $this->mysqli->prepare('INSERT INTO bookings (date, surname) VALUES (?,?)');
$stmt->execute([$booking->getDate(), $booking->getSurname()]);
}
}
Then in your controller, you just use your service as a dependency:
class BookingController
{
public function __construct(protected BookingService $bookingService)
{
}
public function index(Request $request)
{
$boooking = new Booking($request->get('date'), $request->get('surname'));
$this->bookingService->saveBooking($boooking);
}
}
Your DI container takes care of instantiating the mysqli and BookingService class. You can only create value objects in your controller. The necessary data is passed via parameters. This makes for a very clean and understandable code. Everyone knows what each function does, there are no surprises and everything has type specified.
There are a number of techniques to instantiate a variable only once. This is an anti-solution. Please do not use solutions listed here!
Static variable
If you only want a variable to be instantiated the first time the function is called, you can use a static variable.
function foo(){
static $mysqli;
if ($mysqli === null) {
$mysqli = connect();
}
// call the same function in recursive mode and the same connection will be reused
foo();
// do not close the connection manually!
}
This is a bad solution because your function fetches the dependency manually. You should not create functions that have side effects or multiple objectives. A function that connects should not be called from within a function that does something else. This leads to nightmarish code, which is the reason why you are having this problem now.
Using singleton
Singletons are bad for testing and for code readability. Anytime you need to change the dependency, you need to change all the places where the singleton is used. For a better explanation of why they are bad see What are drawbacks or disadvantages of singleton pattern?
Using globals
Globals are very bad for code maintainability. They are the bane of programmers since forever. It's precisely the reason why we have encapsulation and dependency injection.
Using a global would be very similar to using a static variable, except that the side effect is now global.
function foo(){
// declare a variable as global.
// this will instantiate the variable to null if it doesn't exist as a global yet
global $mysqli;
// if it's null, connect
if ($mysqli === null) {
$mysqli = connect();
}
// call the same function in recursive mode and the same connection will be reused
foo();
// do not close the connection manually!
// but if you must close the connection, just set the variable back to null
}
Do not use any of the above solutions! These are examples of bad unmaintainable spaghetti code. A programmer's nightmare. This answer is only supposed to be a warning of what not to do!
Example:
class SimpleClass{
public function foo() {
mysql_open();
//do mysql query here
mysql_close();
}
public function boo() {
mysql_open();
//do mysql query here
mysql_close();
}
}
Or is it better to have one mysql_open in the beginning of the class and one in the end?
Thanks.
EDIT: I use mysqli, this is just an example.
Should I open and close in each page file instead? Like in index.php, cataegory.php should have one open and close each.
Yes, It is bad practice. Here are reasons:
cost of making connectio is high
cannot use transaction during many function is called
every instance has it's own connection. It's too bad
and so on
Use PDO, or make singleton db class youself.
I would recommend wrapping the connection inside of a DAO class that operates as a singleton to manage your connection. In addition to what others have said above regarding prepared statements, and deprecated functions, I'm going to use those same deprecated functions to demonstrate the DAO concept
<?php
class MyGreatDAO{
private static $con = null//late static feature in php 5.3
private __construct(){
}
public static getInstance(){
if($con === null){
$con = mysql_connect($server,$user,$pass);
}
return $con;
}//untested
Basically, the idea is to prevent unnecessary data connections for performance reasons, and just persist the same connection throughout execution. You can use this same class to perform other DB operations as well on $con
I am wondering if my understanding is right.
I placed my database connection parameter on my __construct(), so this means every time the class is instantiated, I also reconnect to my database, right?
private $handle;
public function __construct()
{
$username = "test";
$password = "9712nc*<?12";
$host = "localhost";
$db = "miner";
$dsn = 'mysql:dbname='.$db.';host='.$host;
try {
$this->handle = new PDO($dsn,$username,$password);
}
catch(PDOException $e) {
print $e->getMessage();
die();
}
}
Is this a good practice if I have many request from a certain user? Does this mean every time a user make a request (even if the request is just done minutes ago) the script should first connect to the database? Is there any appropriate way I can preserve my $handle?
BTW: The database connection is working fine.
If the class is instantiated once, then you're going to be just fine. In this case, you open one connection only.
If you instantiate the class several times, or use it as a static class, then you're potentially going to create a connection each time, which is not ideal.
If you keep the classes all active (i.e. you never delete reference to a class once you create it, from memory (I've never tested it) the internals of PHP should actually sort this out for you, and you'll still only have the one connection to the database. But if you lost a handle to the class you created, then the PDO will be destroyed and you start again. If you are using as a static class (i.e. you call it with class:function()), then you're on the wrong path.
There are two common solutions, and you'll find arguements for and against both of them.
1) Use a global for storing your DB connection. You create the $handle = PDO and store $handle as a global variable. Easy to pass around. Easy to overwrite - I'm not going to debate here.
2) Create a "static" class (commonly called a Singleton) that you recall. The basic structure would be
private static $ThisObj;
private static $handle;
public static function getInstance() {
if( !(self::$ThisObj instanceof SoapDB) ) {
self::$ThisObj = new SoapDB();
try {
$this->handle = new PDO_Handler('mysql:dbname=' . DB_NAME . ';host=' . DB_HOST, DB_USER, DB_PASS);
$this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
// Error Here
}
}
return self::$ThisObj;
}
Using this, you would normally create a separate DB class as a singleton. Using Singleton vs Global: your call (after research).
3) The third answer is if you are only ever calling your class above as a static (i.e. you call class::function()) then you can just make the $handle as a static and actually your problems should be wonderously solved. Essentially you're creating a Singleton, with the database as one of the properties.
Sorry that there's no wrong or right answer.
Edit based on comment "What's a static class":
Strictly speaking, I should say "class with static properties". To explain, normally you create a class with the syntax:
$myClass = new class();
$methodResult = $myClass->method();
and then do lots of nifty little things with $myClass by calling functions. You can then drop reference to the class, lose the properties (variables) and will reinitilaise later on.
A static class (for the purposes of this answer) is one where you have static properties. Normally (not absolutely) they are called by going.
$methodResult = class::method();
You don't hold on to the class - it gets initiated, used and dropped. However, if you store properties (vars) as static then each time you use that class, those properties will still exist in the state they last were. So method can set $this->MyVar = 'something' and next time, $this->MyVar will still be something.
Very useful for compartmentalising your code, stops functions overwriting others and can make unit testing easier.
(Note - I'm generalising to make it simpler. But it should give you an idea of the processes.)
You should use singleton.
try google 'mysql php singleton'
eg.
http://www.swhistlesoft.com/blog/2011/08/05/1435-mysql-singleton-class-to-allow-easy-and-clean-access-to-common-mysql-commands
So I know that questions with 'what is the best' in their title aren't supposed to be asked, but really.. how should you do this?
We have a database class and, for example, a user class. A user class will get methods such as create() and update(), which will need to do database stuff.
As far as I know there are 2 main options, passing on the database object in every __construct() or make the database class static.
(Any other tips about OOP + database driven websites are also appreciated)
A very common pattern here is to make the database class a singleton construct, which is then passed to every object constructor (that is called Dependency Injection).
The purpose of making the database object a singleton is to ensure that only one connection is made per page load. If you need multiple connections for some reason, you would want to do it a different way. It's important to pass it via the constructors though, rather than creating the database object inside an unrelated class so that you can more easily test and debug your code.
// Basic singleton pattern for DB class
class DB
{
// Connection is a static property
private static $connection;
// Constructor is a private method so the class can't be directly instantiated with `new`
private function __construct() {}
// A private connect() method connects to your database and returns the connection object/resource
private static function connect() {
// use PDO, or MySQLi
$conn = new mysqli(...);
// Error checking, etc
return $conn;
}
// Static method retrieves existing connection or creates a new one if it doesn't exist
// via the connect() method
public static function get_connection() {
if (!self::$connection) {
self::$connection = self::connect();
// This could even call new mysqli() or new PDO() directly and skip the connect() method
// self::$connection = new mysqli(...);
}
return self::$connection;
}
}
class Other_Class
{
// accepts a DB in constructor
public function __construct($database) {
//stuff
}
}
// Database is created by calling the static method get_connetion()
$db = DB::get_connection();
$otherclass = new Other_Class($db);
// Later, to retrieve the connection again, if you don't use the variable $db
// calling DB::get_connection() returns the same connection as before since it already exists
$otherclass2 = new Other_Class(DB::get_connection());
Another method is to create your database class directly extending either mysqli or PDO. In that case, the __construct() method supplies the object to getConnect(), as in
public static function get_connection() {
if (!self::$connection) {
self::$connection = new self(/* params to constructor */);
}
return self::$connection;
}
Well, what you can do is to have the database access layer in one object, which is then passed to your objects, respecting the inversion of control pattern.
If you want to dig a bit into this direction, have a look into dependency injection (DI): http://en.wikipedia.org/wiki/Dependency_injection
Having a singleton is usually a bad idea as you will end up having problems when testing your code.
Having the database access logic within a model class such as User violates the separation of concerns principle. Usually DAO (Data Access Object) handles db related concerns.
There are ORM frameworks such as Hibernate, which handle mismatch between OO and relational models quite well, potentially saving a lot of manual work.
I'm really surprised that no one said this, but here it goes: ORM.
If your weapon of choice is PHP, then the major options are Propel and Doctrine. They both have many strengths and some weaknesses, but there's no doubt that they're powerfull. Just an example, from Propel's (my personal favourite) user manual:
// retrieve a record from a database
$book = BookQuery::create()->findPK(123);
// modify. Don't worry about escaping
$book->setName('Don\'t be Hax0red!');
// persist the modification to the database
$book->save();
$books = BookQuery::create() // retrieve all books...
->filterByPublishYear(2009) // ... published in 2009
->orderByTitle() // ... ordered by title
->joinWith('Book.Author') // ... with their author
->find();
foreach($books as $book) {
echo $book->getAuthor()->getFullName();
}
You won't get more OO than that!
They will handle a lot of things for you like for one, abstracting your data from the database vendor. That said, you should be able to move (relatively painlessly) from MySQL to SQL Server and if you're building your own tools for web applications, then beign able to adapt to different environments is a very important thing.
Hope I can help!
Hey have a look at ORM's. Let them do the hard work for you? fluent nhibernate or microsofts entity framework.
I could be misunderstanding your question. Sorry if so
My question is:
Can I still do query's from within an object like this:
$result = mysql_query ($q,$dbc)
or
trigger_error("Query: $q\n<br />MySQL Fout: " . mysql_error($dbc));
by passing the global dbconnection variable $dbc to the constructor
or is there a better way?
Or creating a singleton class for the databaseconnection, but
I see a lot off negativity that people are writing about it.
I am new to making objects, so I don't know if I mayby have to do it all a little
different, with the db I mean.
thanks, Richard
If you looking for database abstraction, why not consider using the DB classes provided by Zend Framework.
They also include a way to set an adapter as the default, making it a snap to perform operations.
Add to that the fact that Zend_Db defaults to using parameterised queries instead of old fashioned quoted ones, thus adding security and peace of mind.
using globals is pretty much a bad idea, its far too easy to accidentally overwrite one! along with all the other reasons you will find for not using them with a quick google.
Making a db connection with Zend Framework is a snap,
$db = Zend_Db::factory('Pdo_Mysql', array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test'
));
It really is as simple as that. you can then either make your table classes to provide quick access to individual tables, or use the select and statement objects for more advanced joined querys.
Also, with Zend Framework, you do not have to use the whole stack, you can simply use just the DB components if you like.
If you don't want to use Zend Framework for this, I would strongly recommend you consider alternatives such as an ORM like Doctrine over writing your own DB abstraction. you will end up with a monster very quickly, and an ORM or Zend Framework have a great many developers squashing bugs, and even more reporting any that are there.
Yes, you can pass the database connection around like that.
IMHO it makes coding a little harder but testing a lot easier.
Here's how you would use it:
class DB {
private $dbc;
public function __construct($dbConn) {
$this->dbc = $dbConn;
}
public function runQuery() {
mysql_query($query, $this->dbc);
}
}
Pass the variable. Singletons have a bad reputation for a reason - they were invented to solve a very specific problem, and they didn't even do that particularly well. Don't use them as a way to avoid passing variables around, that's how it should be done.
I use a singleton class for this purpose, but I still pass around my class variable through globals.
The reason the singleton class was created in the first place was to make sure that only one instance of a class is ever created. In this case, I want to make sure that only one instance to the database is ever created. By placing the class as a singleton class, anyone who writes code that interfaces with this class will get the same connection. But, it is still not a replacement for globaling the variable.
For the Singleton class, here is an example:
class datbasebase
{
static $class = false;
static function get_connection()
{
if(self::$class == false)
{
self::$class = new database;
}
else
{
return self::$class;
}
}
// This will ensure it cannot be created again.
protected function __construct()
{
$this->connection = mysql_connect();
}
public function query($query)
{
return mysql_query($query, $this->connection;
}
}
$object = database::get_connection();
The main reason I do it this way instead of simply passing around the connection is purely because I don't want to repeat code over and over. So it is a time saver to have my query, connect, and various other DB functions in the same class.