Lets put the case that we've got two separate classes, each owns a mysqli object to use for database operations.
class A{
protected $mysqliObject;
public function __constructor(){
$this->mysqliObject=new mysqli(...)
}
public function doSomething(){
$this->mysqliObject->query(...);
}
}
class B{
protected $mysqliObject;
public function __constructor(){
$this->mysqliObject=new mysqli(...)
}
public function doSomething(){
$this->mysqliObject->query(...);
}
}
The doSomething() methods use the $mysqliObject for a database query (SELECT, UPDATE, DELETE, etc...). I want to do the following outside:
// Start point
$aObject=new A();
$bObject=new B();
$aObject->doSomething();
$bObject->doSomething();
// End point
...but I want to roll back both queries if any of them fails. How can I do that?
Can I create a brand new mysqli object at "Start point", and use it to commit or rollback at "End point" the database query of class A and class B?
Do I have to create outside, and pass the same $mysqliObject to the __constructor() of class A and class B, and use that to rollback or commit (outside).
Would like to see more techniques with pro-con's.
Each database connection object you have represents a different connection to the database, even if the connection is to the same database server. Each connection is completely independent of each other, so a transaction started in one connection will be invisible to the other connection.
If all your database access is to the same server, then just create a single connection and pass it to anything that needs access to the connection. Then the transaction will be application-wide.
class ClassThatNeedsDbAccess
{
protected $connection = NULL;
protected function doQuery ($query)
{
return ($this -> connection -> execute ($query));
}
public function __construct (PDO $connection)
{
$this -> connection = $connection;
}
}
class OtherClassThatNeedsDbAccess extends ClassThatNeedsDbAccess
{
}
$myDb = new PDO ('dsn_goes_here');
$obj1 = new ClassThatNeedsDbAccess ($myDb);
$obj2 = new OtherClassThatNeedsDbAccess ($myDb);
If you're talking to different database servers, then you probably should wrap all the connections in an object that can coordinate the database activity. It will be that object's responsibility to track which database connection has a transaction in flight.
Use one MySQL object - connection for all your business logic... take a look at singleton pattern. You can pass it to constructor or you could use static class method to get mysql object.
Then it's a matter of you where you start end transaction, connection must be the same. Best would be abstract it into some general database access layer.
Related
I have a CMS that is failing when more than one person is logged in. I think the problem may be that I'm not closing databases properly. Here is the basic setup:
I have a master class called Mysql. The __construct() method looks something like this:
class Mysql {
protected $conn;
function __construct() {
if(!$this->conn) $this->conn = New mysqli(SITE_HOSTNAME, SITE_USERNAME, SITE_PASSWORD, SITE_DATABASE);
}
All of my classes are descendants of this class, and so whenever they are instantiated, they get their own connection.
I'm using prepared statements to protect against sql injection. A sample method might look like this:
function foo($blog = 0) {
$query = "SELECT catid, catname
FROM category
WHERE blog = ?
ORDER BY catname ASC";
$result = array();
if($stmt = $this->conn->prepare($query)) {
$stmt->bind_param('i', $blog);
$stmt->execute();
$stmt->bind_result($catid, $catname);
while($stmt->fetch()) $result[$catid] = stripslashes($catname);
$stmt->close();
return $result;
}
}
The Mysql __destruct() method looks like this:
function __destruct() {
if($this->conn) $this->conn->close();
}
Is my problem that I am not closing my connections properly, or that I do not have enough active connections?
My provider says that I have 30 simultaneous connections available. Not enough?
Thanks for your help.
The Problem
All of my classes are descendants of this class, and so whenever they
are instantiated, they get their own connection.
The problem with the way you are doing it is that every single instance of any class that inherits Mysql is opening a connection to the Mysql server that lives until the request is completed, or the variable destructed (unless you are killing these objects manually, that's at the end of the request). If you have 30 instance of classes like this, then you have maxed out your connections.
Fixing The Problem
Your classes shouldn't all be inheriting this Mysql class that represents your interface to the database.
Instead, you should be passing a single instance of this Mysql class where it's needed.
There are two ways this could be done effectively:
Dependency Injection
class SomeClass {
protected $db;
public function __construct(Mysql &$db) {
$this->db = $db;
}
public function functionThatNeedsDatabase() {
$this->db->doSomethingWithTheDatabase();
}
}
$db = new Mysql(); //A single instance of Mysql class has been created.
$someClass = new SomeClass($db);
$someClass->functionThatNeedsDatabase();
Pass to Method When Needed
class SomeClass {
public function functionThatNeedsDatabase(Mysql &$db) {
$db->doSomethingWithTheDatabase();
}
}
$db = new Mysql(); //A single instance
$someClass = new SomeClass();
$someClass->functionThatNeedsDatabase($db);
Your problem is "All of my classes are descendants of this class, and so whenever they are instantiated, they get their own connection." In PHP connection are automatically closed when the script ends. You really only need 1 connection per user. You should create an instance of your DB class and pass that object into all the classes that need to use it (Dependency Injection pattern).
30 connections is not a whole lot, but that is sufficient for a lot of traffic. I would avoid using persistent connections. Read the documentation thoroughly on that, there are plenty of warnings.
I have a class userdb in which I am declaring a function that returns the connection to the database:
return $con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
I have various functions, even across other classes, where I have to access $con (e.g. to pass a query or to fetch data), but I can't access this variable.
Is there a better way to define and use a database class? Remember that I have other classes where I need to access the userdb class.
I would advise you to use the Singleton Pattern for this:
In your userdb class, declare a static property $scon:
private static $scon;
and assuming the function you mention above is named createConnection(), you should create the folowing static method:
public static function connect() {
if (empty(self::$scon)) {
$instance = new userdb();
self::$scon = $indtance->createConnection();
}
return self::$scon;
}
With this, you will be able to access your userdb connection with:
userdb::connect();
Also since this is a singleton, it will only connect once, and use that connection until the end of the script.
Note (on dependency injection): Since #KevinM1 mentioned Dependency Injection, I must add that it is also a possible, and far superior solution. It requires you to create a setConnection() method (or an Abstract ancestor) for all your classes using a database connection, and during the instatiation of these classes you may use a Factory to add the required connection to the object. This should be wrapped inside some class loader, which is avare of your model structure.
See, peace of cake, but for small and fast developement I would stick with the Singleton ;)
If it's in a class, store the instance in a property:
class userDB
{
public $dbCon = false;//because you want to access the instance
//from outside the class, I have made the property public
function connect()
{
$con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
$this->dbCon = $con;
}
}
TO access it outside of the class:
$useDBInstance->dbCon;
return $this->con
return this way from your class and call it this way..
$this->classObject->con->prepare();
Checkout my video tutorial + code for an alternative to global PHP variables.
You're doing it wrong there. You need to use a static variable if you plan to create your connection in a function and store it there. Otherwise you'll keep connecting on every function call. My tutorial explains this very concept of static variables within regular functions.
If it's not clear enough, let me know and I'll try to answer your questions.
Here's some code to accompany this:
/**
* Arguments are none or [$db, [$user, [$pass[, $host]]]].
*
* #return PDO
*/
function PdoDb(){
static $con = null; // I'm explicit :)
// Every time you pass Arguments you reconnect
if(func_num_args()){
$args = array_pad(func_get_args(), 4, null);
list($db, $user, $pass, $host) = $args;
if(empty($user)) $user = 'root';
if(empty($host)) $host = 'localhost';
$con = new PDO("mysql:host={$host};dbname={$db}", $user, $pass);
}
if(empty($con)){
trigger_error('Provide arguments to connect first.', E_USER_ERROR);
return null;
}
return $con;
}
// First run (provide arguments to connect)
PdoDb($db, $user, $pass, $host);
PdoDb($db); // Works if you connect root#localhost with no password
// From here on (it returns PDO)
PdoDb()->DoStuffOfPdo();
Once connected it stays that way. But you can reconnect at will to by providing arguments.
Well, $con will already be an object, as it's instantiating a new PDO object. Unless you're trying to add functionality to your PDO object, wrapping it is pointless.
That said, the best way to share your userdb/PDO object (depending on whether or not you stick with the wrapper) with other objects is to use Dependency Injection. That's a fancy term for passing your db to whatever object needs it. Since objects are defaultly passed by reference in PHP, if you create your db object first, all objects that receive it as a constructor/method argument will be using that same single instance.
EDIT: Link to Dependency Injection implementation
EDIT2: Clarification on DI in small projects -
The normal DI pattern generally requires a special object called a DI Container. This is a special use object that automatically injects the dependency into the object that needs it. For small projects, it's overkill. The simple, low complexity version of DI is simply:
class SomeClass {
protected $db;
public function __construct($db) {
$this->db = $db;
}
}
class SomeClass2 {
public function SomeMethod($db) {
// do something with the db
}
}
$db = new PDO(/* connection string */);
$obj = new SomeClass($db, /* other constructor args */);
// or
$obj2 = new SomeClass2(/* constructor args */);
$obj2->someMethod($db, /* method args */);
The magic is that since objects are passed by reference by default in PHP, $obj and $obj2 are using the same db connection.
The whole idea is to not blow apart scope or encapsulation by having a static method, and to ensure that classes and their methods are up front about what they require in order to work.
Singletons do the exact opposite. They're accessed through static methods, which bypass scope, and since they're invoked and not passed, they never show up in method signatures, so anyone not familiar with the code won't be aware of that hidden requirement. Even Erich Gamma, one of the people who helped codify the Singleton Pattern has regrets about it:
I'm in favor of dropping Singleton. Its use is almost always a design smell.
In PHP, where there's no concept of shared memory, and where scripts execute once per request, the only reason to want to use a singleton is to have easy access to a single resource. Since objects are passed by reference, a single instance can be shared with multiple objects naturally. From there, it's about good design and delegation.
use singlton class implimentation
class connectdb
{
protected static $_instance = NULL;
private function __construct()
{
}
public function getinstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function connect()
{
$this->connection =new PDO("mysql:host=$host;dbname=$db", $user, $pass);
}
}
for using a variable within a class function or independent function you need to place a global keyword
$conn=mysql_connect();
function test(){
global $conn;
}
now $conn will be available within the scope of test function, and it will be available everywhere when defined at the top of the script. For class also you need to do the same thing, make a object of a class and declare it as global within a function
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
I am making my first steps in the OOP world - please bear with me.
I know that having many ongoing mySQL connections open at the same time can be fatal for performance, so it should be a good idea to make a database class that takes this into account.
Is $this->session->write(...); going to result in a new mySQL connection being opened each time?
Or is that up to the "persistent connection" feature in mySQL?
Here's the code:
abstract class database {
function __construct() {
//mysql_connect()
}
}
class session extends database {
function write () {
// mysql_query(--.)
}
}
Is session handler some kind of specialized type of database? It is not, so don't use inheritance (a is a relationship). Session handler uses database so you should use composition (a has a relationship):
class Session {
protected $db;
public function __construct(DB $db) {
$this->db = $db;
}
public function write() {
$this->db->query(...);
}
}
$db = new DB(...);
$session = new Session($db);
Also, don't use mysql_*() functions. Use much more powerful PDO.
Returning to your question... mysql_connect() will be executed every time you create a new Database object. However in this case Session is an object of type Database so every time you write new Database() or new Session() the constructor is invoked, therefore mysql_connect() is invoked as well.
PS. mysql_connect() function won't create a new connection if specified connection already exists. Check 4th argument of this function to learn more.
mysql_query will create a new connection only if no previous mysql connection has been made. Otherwise, it will either use the connection you specify or the last connection opened with mysql_connect. http://php.net/manual/en/function.mysql-query.php
Why not
class database {
function __construct() {
//mysql_connect()
}
function write() {
//query the DB
}
}
I'm not sure of the syntax, I don't do OOP PHP. Anyway, in your structure above a new connection would be opened for each "session" instance so assuming you only create one instance of "session" you won't be openeing loads of database connections.
Perhaps you can help. I have a main class that creates a MySql connection. Then I extend this class. I wasn't able to access the connection unless I did a parent::__construct(); and recently while doing this I got an error message that I was out of connections.
So how do program this so it doesn't run out of connections and can access the database connection.
class Common
{
var $mysql;
function __construct()
{
$this->mysql=new mysqli($this->dbHOST, $this->dbUSERNAME, $this->dbPASSWORD, $this->dbNAME);
}
}
class Role extends Common {
function __construct()
{
parent::__construct();
}
}
I think there is a fundamental problem with your class structure: You don't need a connection per object, you only need a copy of the connection resource per object.
My preferred way out of this is to create a database handler that has a singleton call. Now it can be called anywhere and it will always return the same connection handler. This is also an excellent way to hide automatic initialization.
The solution was borne out of the realization that a class representing a database row is actually quite different from a class that is a database connection. An app will deal with many many rows but rarely, if ever, will deal with more than one connection. Another way of putting this is the difference between the IS-A and HAS-A definitions: it doesn't make sense to say "a database row class IS-A database connection". It does make sense to say "a datbase row class HAS-A database connection".
Make sure you close the connection when the object is destroyed. That is, add a __destruct() method that closes the connection.
If the Common class is the one that opens the connection in its __construct() method, then it should be the one to close it in its __destruct() method. If you don't define a __destruct() method on the Role class, then it looks like PHP won't call the parent's __destruct() automatically. (I haven't tested this, though.) A simple solution is to add a stub __destruct() method that just calls parent::__destruct().