On 4/13/07, Ovid <[EMAIL PROTECTED]> wrote: > --- Bill Moseley <[EMAIL PROTECTED]> wrote: >> I would expect that most applications need a shared dbh -- anything >> that uses transactions, of course. And, therefore perhaps there was a >> standard approach. > > You know, I was rather surprised about that myself. I've heard so many > good things about Rose that I had to check it out. So far, I'm > impressed enough that I've wondered if I missing something very > obvious. In my test suite, I temporarily overrode init_db to give me > that because running tests without transactions is very painful > (particularly when using Test::Class).
It's expected that any non-trivial set of RDBO-based classes will override init_db() in the common base class. The default init_db() looks like it does because it's the "most granular" solution. It makes each operation (and each transaction, for that matter) happen in isolation. Without "real" transaction support in the db, this is probably not an important distinction. But when the db supports real transactions, sharing database connections by default can result in "spooky actions at a distance," as they say. E.g., a rollback in once piece of code could roll back uncommitted changes in a totally unrelated bit of code, all because every object is really sharing the same database connection (and therefore the same database session). This is a phenomenon a beginner might not be aware of, so the default behavior allows blissful ignorance of transactions, at the cost of more connections. When it comes time to learn/use real transactions, some decisions have to be made db connection management. (The docs should probably contain more example scenarios...patches welcome :) The most common "shared" scenario is probably when one db is shared among a "class family" (e.g., My::FooDB::* shares one db, My::BarDB::* shares another). This is usually done by overriding init_db() in the common base class for each family, returning either a single Rose::DB-derived object, or multiple Rose::DB-derived objects all "stuffed" with the same $dbh. Apache::DBI simplifies this in the mod_perl environment by making all Rose::DB-derived objects of the same type and domain always share the same $dbh. It also handles ping()ing and calling rollback() at the end of each request to prevent locks in the case of failures mid-transaction. My personal preference is to make my init_db() routines look like this: package My::DB::Object; ... sub init_db { My::DB->new('sometype') } I use Apache::DBI under mod_perl, so in that environment one $dbh is shared among all objects in a class family. In offline scripts, I usually manually create and manually share My::DB object(s) as appropriate. I know some people find this tedious, but I like the clarity it provides. Regardless of which sharing scenario you choose, the amount of work involved (as measured in lines of code) is rarely large. For example, implementing the "one db is shared among a 'class family'" policy is as simple as this: package My::DB::Object; ... our $DB; sub init_db { $DB ||= My::DB->new('sometype') } If you really don't want to use Apache::DBI, implementing its ping() and rollback() behavior can be as simple as hooking the following bits of code to start and end of each request: # At the start of each request My::DB::Object->init_db->dbh->ping(); ... # At the end of each request My::DB::Object->init_db->rollback(); ... (Error handling and automatic re-connection omitted.) In general, I get suspicious when I see huge swaths of code dedicated to this sort of thing. No matter what the intended policy, there's usually a simple way to implement it under RDBO. Finally, remember that RDBO will share a single db object among related clusters of objects by default. For example, in a Manager call like this (and in the absence of a "share_db => 0" parameter): $products = My::Product::Manager->get_products(...); every product in @$products will share the the same db object (and therefore the same database connection). Similarly, when group-saving objects: $p = My::DB::Product->new(...); $p->vendor(My::DB::Vendor->new(...)); $p->colors({ name => 'red' }, { name => 'blue' }); $p->save; # save product with vendor and colors the final save() call will be sure to share a single db object ($p's) among all objects, which will all be saved in a single transaction. So even with the box-stock behavior of init_db(), certain kinds of db sharing does happen when necessary. It's hard coming up with beginner-friendly defaults while also allowing "anything" to be done by experience users, but that's the balance I'm trying to strike with RDBO. -John ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys-and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Rose-db-object mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/rose-db-object