tags:

views:

99

answers:

3

I've been a procedural programmer for over 4 yrs and it's time to start looking into OOP. With that said, let's say I needed to call two methods in my class. Each method requires a connection to the DB so that's two trips to the DB, which also opens multiple connections. Can this be avoided by having some sort of code in the application layer (constructor?) or does a connection pool have to be setup on the DB side? And just for kicks, I'm not using mysql; I'm using mongodb with codeigniter.

Here's what I have so far, not sure if it's ideal to use?

Here's where I setup my DB info:

database_conn.php

class Database_Conn extends Model {

    function _connect() {
        $m = new Mongo("localhost:27017", array("persist"=>"x"));
        $db = $m->selectDB( "foo" );
        return $db;
    }    
}     

sample model file

class Home_model extends Model {

    public function __construct() {
        // Establish connection to "profiles" table
        $this->db_conn = Database_Conn::_connect()->selectCollection( "profiles" );
    }

    function getMyProfile($username) {
        $data = $this->db_conn->findOne(array("username" => $username) );
        return $data;
    }

    function getAll() {
        $data = $this->db_conn->find(); 
        return $data;
    }
}
+5  A: 

you should use singleton pattern

EDIT: the way you did it, it is possible to call _connect multiple times, which means reconnecting.

singleton implementation usually means you have to make constructor private/protected and define a getInstance method which creates connection on first call and returns the created connection on later calls.

this is what i would do:

class Database_Conn extends Model {

    static protected $_instance;

    protected $db = null;

    final protected function __construct() {
        $m = new Mongo("localhost:27017", array("persist"=>"x"));
        $this->db = $m->selectDB( "foo" );
    }

    static public function getInstance() {
        if (!(self::$_instance instanceof self)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function getConnection() {
        return $this->db;
    }

    final protected function __clone() { }
}

and then use Database_Conn::getInstance()->getConnection() to get the connection object.

kgb
i thought this is bad for apps that eventually needs to scale?
luckytaxi
singleton is a way to create an object which is instantiated exactly once. how can it reduce scalability? please tell me)
kgb
Sorry, I was thinking of something else (dont ask). I understand what you're saying, I thikn I'm doing that now. Take a look at my code above. Thanks.
luckytaxi
The example can reduce stability by returning an existing connection no matter what. In many DBMSes, a connection that's currently returning a result set is "busy", and can't be used for a new query til the results are fetched or discarded. So you end up waiting on previous operations to finish or you get an error or even deadlock, which isn't the case if you use a new connection. Granted, it isn't the singleton that's necessarily doing that, but "instantiated exactly once" doesn't play well with "more than one connection" in your example.
cHao
@cHao - i think luckytaxi's purpose is NOT having multiple connections. php is not fit for multithreding, so we'll have to wait for the query to complete anyway, connection is not going to be used for any other purpose during that time
kgb
Code seems to work thanks, however I had to remove "protected" in order for it to work. Must be CI doing this. "PHP Fatal error: Call to protected Database_Conn::__construct() from context 'CI_Loader' in /var/www/html/project1/@codeigniter/libraries/Loader.php on line 184"
luckytaxi
@luckytaxi the whole point of singleton is NOT to call(and not to be able to call) __counstruct(otherwise you will end up with multiple connections), so you should use Database_Conn::getInstance()->getConnection() only
kgb
I understand, but I think codeigniter doesn't allow singleton for some reason. your code works, i've tested it using Database_Conn::getInstance()->getConnection(). I had to remove "protected" from the construct for it to work.
luckytaxi
@kgb: you don't need multithreading to have problems with a single connection. All you need is to be fetching result rows one at a time (as was common before the advent of PDO and the like), and need to do another query at the same time. Unless you're buffering the rows, the connection can be "busy" either until the last record is fetched, or until you free the result set however the API lets you do it.
cHao
@chao, are you saying singleton would be a bad choice? Let's say one was to build a clone of FB with millions of ppl accessing your database farm.
luckytaxi
@luckytaxi: I'm saying forcing all your DB access into a single connection could be a bad choice. By extension, a singleton representing the sole DB connection would be bad as well. However, were your singleton to represent the DB itself, and provide the ability to get a connection (that could, for example, be drawn from a pool of available, possibly persistent, connections), it might not be so bad. Course, at that point, it'd be kinda hard to justify the Singleton pattern for such a thing. But personally, i find it hard to justify singletons almost anywhere.
cHao
@cHao, so what would you suggest then?
luckytaxi
@luckytaxi: Take a look at spinon's answer. It's quite similar to what i'm talking about, except i'd replace "open" with "idle".
cHao
+5  A: 

You should look into a manager class for your db connections. Then you can have one central place where you request connections from. If there is already an open connection the manager can return that instead of returning a new connection.

This would be one approach. There are tons of examples out there about how to implement something like this. There already some for mysql and mssql. But you could surely extend for your db.

spinon
this sounds familiar to what kgb has shown, no?
luckytaxi
It does. But if you look when we posted they are right at the same time. Though he also made an edit after to include more.
spinon
no problem, I did realize that but wanted to make sure I'm understanding the concept correctly. Thanks again!
luckytaxi
My bad. I thought you were implying that I just copied what he wrote. Yeah the two are the same. A singleton so that only one instance of the class is created. That way it can control all requests for connection and reuse any open ones.
spinon
Should I worry about closing the connection eventually?
luckytaxi
No. You only work against the manager not the connection. You wouldn't want to close the connection because the manager will not know that you closed it and it will hand that connection out to other people requesting and it would obviously not work.
spinon
+1  A: 

Use a database layer. Dibi is a great library in this case. http://dibiphp.com

Jan Kuča