aspose file tools*
The moose likes JDBC and the fly likes Data Access Objects: static methods Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Databases » JDBC
Bookmark "Data Access Objects: static methods" Watch "Data Access Objects: static methods" New topic
Author

Data Access Objects: static methods

Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

Is there a best practice on whether or not to use static mehtods in a DAO classes? Any benefits or anti-patterns either way?


GenRocket - Experts at Building Test Data
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
This was just discussed one or two weeks ago either in this forum or one of the Java in General ones -- probably this one I'd hope. Actually, I assume you're talking about using static methods instead of a DAO instance, correct?

The main problem with this is that you can't ever swap out your DAO for something else: either a different implementation or a mock object for testing. You're much better off creating an interface and implementation. Go ahead and use a singleton instance of the DAO; tools like the Spring Framework make this a snap. Check out the ORM forum for recent discussions on using Spring for this.

Static methods should be reserved for things that won't ever change. While it's conceivable that you may want to swap out a different implementation of the java.util.Math methods, it's pretty unlikely. But to test a business object that uses a DAO, it is much nicer to use a mock DAO (jMock or EasyMock; I slightly prefer the former) so you can test the business object in isolation (this is the whole point of unit testing).

If you use static methods, all your tests have to run against a real database or you need to swap in a different JAR with a different class that has the same static methods. Ouch!

So turn it around: what specific reasons do you have for using static methods? What do they buy you? Maybe we can give you other ways to get the same benefits without them.
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

Originally posted by David Harkness:
This was just discussed one or two weeks ago either in this forum or one of the Java in General ones -- probably this one I'd hope. Actually, I assume you're talking about using static methods instead of a DAO instance, correct?

The main problem with this is that you can't ever swap out your DAO for something else: either a different implementation or a mock object for testing. You're much better off creating an interface and implementation. Go ahead and use a singleton instance of the DAO; tools like the Spring Framework make this a snap. Check out the ORM forum for recent discussions on using Spring for this.

Static methods should be reserved for things that won't ever change. While it's conceivable that you may want to swap out a different implementation of the java.util.Math methods, it's pretty unlikely. But to test a business object that uses a DAO, it is much nicer to use a mock DAO (jMock or EasyMock; I slightly prefer the former) so you can test the business object in isolation (this is the whole point of unit testing).

If you use static methods, all your tests have to run against a real database or you need to swap in a different JAR with a different class that has the same static methods. Ouch!

So turn it around: what specific reasons do you have for using static methods? What do they buy you? Maybe we can give you other ways to get the same benefits without them.


Thanks for the information. What reasons? Not having to create a new object, saving a line of code. Pretty insignificant reasons really.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
I certainly didn't mean to imply there aren't valid reasons. I'm not badgering the witness, honestly!

Now that I'm using Spring I no longer use the Singleton pattern in the following form, but my DAOs are effectively singletons. All of the business objects that use the DAOs reference a single instance, but that doesn't preclude having multiple instances for different BOs or instiating a new one for each request (Spring supports this model too). But if you're not using a similar framework, the old standby Singleton pattern works pretty well.A common anti-pattern is to have the factory create the DAO in the inst() method if it hasn't been created yet, but then you're limiting yourself to a single implementation (though you could have it instantiate the default implementation I suppose). Instead, you'll need to bootstrap your DAOs in a startup servlet or some other way.

To use it is nearly as easy as static methods:You can of course make the instance available in a context object or anywhere else you like from there.
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

Originally posted by David Harkness:
I certainly didn't mean to imply there aren't valid reasons. I'm not badgering the witness, honestly!

Now that I'm using Spring I no longer use the Singleton pattern in the following form, but my DAOs are effectively singletons. All of the business objects that use the DAOs reference a single instance, but that doesn't preclude having multiple instances for different BOs or instiating a new one for each request (Spring supports this model too). But if you're not using a similar framework, the old standby Singleton pattern works pretty well.A common anti-pattern is to have the factory create the DAO in the inst() method if it hasn't been created yet, but then you're limiting yourself to a single implementation (though you could have it instantiate the default implementation I suppose). Instead, you'll need to bootstrap your DAOs in a startup servlet or some other way.

To use it is nearly as easy as static methods:You can of course make the instance available in a context object or anywhere else you like from there.


You are awesome David. That is exactly the kind of information I was looking for. Thanks a million.

Question, in the UserDaoFactory, when/how does getInst get called so that the instance is created? Instead, you'll need to bootstrap your DAOs in a startup servlet or some other way. If this is the answer, could you explain that a bit more? Thanks.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Originally posted by Gregg Bolinger:
Question, in the UserDaoFactory, when/how does getInst get called so that the instance is created? Instead, you'll need to bootstrap your DAOs in a startup servlet or some other way. If this is the answer, could you explain that a bit more? Thanks.
No problem, glad to help!

Yes, that's one way to do it. Let me show the old way first, which does work well enough but as I said should be left as the "default." Since you're probably only going to create one implementation per DAO anyway, this works just fine.Note that there are a couple of problems with this. For one, the JDBC-based DAO probably needs a DataSource in its constructor, so where does that come from? Either the DAO or the factory could look it up, but now they need to know where to get it from.

Another issue, which is arguably very minor in most cases, is that if two threads call that at just the right time, two DAOs will get instantiated. As long as their implementations don't depend on it being a real singleton, this is no big deal as the "extra" one will just be garbage collected soon enough.

The other option that I mentioned is bootstrapping. This is just a general term for setting up all your objects up-front. If this is a webapp, there are a couple ways to do this. I'm not as familiar with setting up the web tier (just using it), but I do believe there's some sort of ServletContext/Filter concept of an initialization class that the web container will call when it spins up before it accepts any requests. This is the ideal place.

The way I've done it, not knowing any better, is to create a StartupInitServlet (that's just the name) with an appropriate init() method and set it to have exactly 1 initial servlet created. Also, I don't bind it to any path or uRL so no one else can call it externally. The web container will preinstantiate servlets that you specify so this has the same effect. As I said, this is a hack that probably has a very nice solution nowadays.

I guess I'd be remiss if I didn't plug the Spring Framework a little more. First, my only connection with it is that I think it rocks. I've just ported a fairly sizable EJB (session and entity beans) to Hibernate and Spring, and I must say it was amazingly easy to set this stuff up. Now I have an application context XML file that replaces all that ugly singleton code I showed you above.

The business objects are wired to the DAOs they need; each DAO is wired to a single Hibernate SessionFactory which is wired to the DataSource. The business objects use Spring's TransactionProxy to enjoy declarative transaction demarcation just like EJBs, and the TransactionProxy knows to delegate to Hibernate as controller.

Check out this thread for some more discussion.
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

Ok, I'm really battling with getting this project done and understanding what the heck I am doing. So I am going work this afternoon on implementing some of your suggestions.

I have another question. I am not going to use Spring. I've been wanting to understand DAO's and using a framework won't help me. However, I have done enough JDBC and SQL to last me a lifetime so I am using Hibernate. Does anyting you suggested change with regards to the above statement?
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Originally posted by Gregg Bolinger:
I am not going to use Spring. I've been wanting to understand DAO's and using a framework won't help me.
I don't understand this statement. What does one have to do with another? Are you thinking that the framework would obviate the need for DAOs, that it has its own DAOs so you won't learn about making your own? I can say that that isn't the case. I had to write my own DAOs.
However, I have done enough JDBC and SQL to last me a lifetime so I am using Hibernate. Does anyting you suggested change with regards to the above statement?
Heh, now I'd absolutely recommend Spring! Hibernate is tough enough, Spring would help you a lot by doing a lot of the grunt-work. But I'll put that aside for now.

Nothing I said above changes now that I know you're using Hibernate. Ideally, your DAOs shouldn't have to change so much based on the persistence mechanism you're using. In practice, of course, it does affect it somewhat. For example, Hibernate will persist collections of related entities when you persist the parent entity. JDBC would not.

There are actually a few threads I was just reading the other night on the Hibernate forums asking about this. The conclusions seemed to be the same: The DAO interface should be as persistence-agnostic as possible, but you'll never achieve complete transparency. My HibernateDao interface adds locking methods (lock, lockForUpdate, and unlock) and cache-related methods (evict and refresh). Other DAOs wouldn't have any use for those.
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

I don't understand this statement. What does one have to do with another? Are you thinking that the framework would obviate the need for DAOs, that it has its own DAOs so you won't learn about making your own? I can say that that isn't the case. I had to write my own DAOs.

Yes, that was what I was thinking. More to come....

Heh, now I'd absolutely recommend Spring! Hibernate is tough enough, Spring would help you a lot by doing a lot of the grunt-work. But I'll put that aside for now.

Well, I've decided to use Hibernate 3 even though it is not an RC yet because of several of the new features. That being said, Hibernate3 and Spring don't work together, easily, yet. See this thread on the Hibernate forum for more details about that. Specifically the following:


If you are in a CMT environment, you should no longer need Spring. AFAICT, people use spring here for four things:

(1) session handling/flushing
(2) transaction management
(3) SQLException mapping
(4) Runtime exceptions model

Well, with hibernate.transaction.flush_before_completion and hibernate.transaction.auto_close_session, (1) is now much, much easier. (2) is handled by CMT. (3) is implemented in the Hibernate Dialect. And Hibernate3 has an unchecked exception model, so (4) is no longer relevant.


So what I want to do is look at your original design and see if I can't modify my project to implement a decent DAO pattern. So with that...

Here is a sample DAO from my project. It's is UserDAO. It extends BaseDAO which I will list first:



I am using the HibernateUtil class from the CaceatEmptor example application, which I am sure you are familiar with.

Now here is my UserDAO class



As you can see, I am not using Interfaces at all. So what I need to do now is change the above code. That should be fun. While I work on that here, do you have any suggestions? Do you see anything really wrong with what I am doing now?

Also keep in mind I am using a Filter called HibernateFilter (also from CaveatEmptor) that commits after the each request has been processed. Things work really well so far as is. But I want to do this the right way.
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

Ok, here is what I have changed so far. I still have the same BaseDAO class. But now I have an interface called UserDAO and a class called HibernateUserDAO that extends BaseDAO and implements UserDAO:



Not really much to that yet.



Then to use this I just do:



This works well too. So what advantage does the suggested UserDAOFactory have? How does it help me?
[ February 15, 2005: Message edited by: Gregg Bolinger ]
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Yes, Spring isn't ready for Hibernate 3. On the Spring forums Rod and crew mentioned that they have H3 classes working, and I see someone posted in that thread you linked that there are H3 classes available.
I'm currently working on a project with Spring + hibernate 3. I started with Hibernate 2.1 but had too many issues with collections and composite keys so I switched to Hibernate 3 and everything worked out of the box.
I do admit that this is an issue going forward as I am dependent on the Spring team continuing to update Spring as Hibernate releases new features.

One thing to note is that #2 requires that you are running in a CMT environment -- Session EJBs. If you're not, then you have to manage transactions yourself somehow, which I see you are in your DAO. However, it's generally accepted that it's better to manage transactions outside of your DAOs.

Your DAOs should just perform data access. Your business objects, the classes that perform actual business logic, should manage transactions. This allows you to combine multiple DAO methods or even methods against multiple DAOs into a single transaction.

For example, say the User object tracks how many Posts the User has made. In the method that posts a new message for a user, you want to create a new Post and update the User's count. Both should be executed in the same database transaction to ensure data integrity. With the DAOs managing transactions, if the Post-create succeeds but the User-update fails, you either have bad data or you need to perform another transaction to "rollback" the Post-create (i.e. delete the Post), but what if that fails? Now you have bad data, period.

Actually, I'm only passingly familiar with how HibernateUtil works. I believe that getSession() will bind the Session to the Thread, correct? This allows multiple DAO calls to share the same session. I see you are starting a transaction, but where do you commit it? I picked up both Hibernate and Spring at the same time, and I wasn't given nearly enough time to do it well, so unfortunately I'm not as familiar with Hibernate utilities and patterns as I'd like.
Originally posted by Gregg Bolinger:
So what advantage does the suggested UserDAOFactory have? How does it help me?
There are two places where it helps. The first is if you ever need different implementations of your DAOs -- say you migrate to the next cool persistence layer. Now you must go through all your code and change "new HibernateUserDAO()" with "new CoolBeansUserDAO()". Granted, with grep this isn't that big of a deal, except that you can't do it at runtime. You must maintain two codebases, one for each DAO implementation.

Now, that reason gets trotted out every time along with not using vendor-specific SQL. But in my 15 years of professional application development, we've never changed the database vendor (though we supported three vendors on one project, but we knew up front), and my current project is the first time we've switched persistence frameworks. Of course, I spent much of that time as a contractor on short assignments, so it's conceivable the rest of the project team had to deal with this.

However, I came onto this project when the BL layer was complete and just built out an EJB layer below it, but it was really a heavy CRUD layer. Therefore, in porting to Hibernate we gutted the entire mess below the BL, and I built out the generic DAO layer I mentioned above. While I could have coded to the original CRUD layer that had been atop the EJB layer, it was so heavyweight and fraught with problems, I found it better and faster to nuke the entire site from orbit (It's the only way to be sure).

The second reason to use some other method of getting a DAO rather than newing it in the client code is for testing. In this port of our system, we were changing so much code that the only way to be really comfortable that I wasn't introducing bugs was to institute unit testing. And the most effective way to do unit testing that I've found and read about is to isolate your units. Testing the business logic is a PITA when you're also testing your database at the same time. First, it's slower, and second, when there's a bug you don't know where the bug is. You have to do more testing to isolate the real problem.

By using interfaces and externalizing the "wiring up" of your business objects to their needed DAOs, you can use mock objects. I don't know if you've read about mock objects, but I originally thought they were stubs that did nothing, so I never used them. Or I created my own stub objects that just returned null or an empty list. In effect, they'd say "sure I'll do what you want ... <does nothing> ... okay done."

However, mock objects are very powerful. You start your test by telling the mock object what method calls and parameter values to expect. Then you make the business logic calls on the real business object. Since the BO is wired to the mock DAO, no database activity happens, but the mock DAO records what calls the BO makes. Then you call verify() on the mock DAO and it makes assertions to verity that the BO did what you expected it to do.

Here's one of the more complex examples from one of my tests. This tests a specific failure case of trying to issue a ticket (OmgData) to a user from a pool of tickets. It tests what happens if the first free ticket according to the OmgSource table turns out to have been deleted. Instead of barfing, I expect it to grab the next ticket, and so on until it actually finds one.As you can see, mgr (the BO under test) will end up making several calls against each DAO. This tests that it makes those calls (and I set up the mock to respond with various return values to "fake" that the first ticket wasn't found but the second ticket was). If any call deviates in any way (wrong parameters or order of calls, etc), it fails the test and tells me what method and parms were incorrect. I follow it up by asserting the state of the domain objects: ticket was assigned correctly to user and given a date, free ticket count decremented by two keys, etc.

Normally, you'd have to set up sample data in the database and reset it each time you run the test. And worse, the only way to validate the test is to look up the results in the database! Yes, there are better tools for this now, like DBUnit, but it's still non-trivial. I found working with mock objects really easy after about an hour of getting used to the most common API elements.

To bring this back to your question, the only reason I can do this easily is because the BO "mgr" is wired to a DAO externally. In the application, Spring wires it to a singleton DAO. In my test case, I just create a mock DAO and wire the BO to it by hand:Since your DAO cannot be a singleton as the constructor sets up a Session instance variable and begins the transaction, you'd simply change the inst() method I gave you to create a DAO each time, but it could do so by using Class.forName() and a bootstrapped classname to instantiate. Of course, do the Class.forName() once and hang onto the Class so you don't look it up each call.

If you decide to move your transaction handling outside of the DAO, then you can make the DAOs singletons by putting the Session acquiring code into each method. This assumes that HibernateUtil.getSession() binds it to the Thread (as a ThreadLocal) as I suspect, but double-check that before you count on it. It's not like creating such a tiny object (one reference field) will cause a drain on your GC anyway.

I hope I haven't rambled too far from your question. It actually helps me to describe this to you as now I can more easily verbalize just why I've done it how I did it.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
One more thing. I wanted to recommend Domain-Driven Design by Eric Evans. I'm only about half-way through it, and sadly got diverted by this porting project, but I really like it so far.

It's main focus is exactly this aspect: Factories and Repositories (DAOs), Domain Objects (Entities and Value Objects), query abstraction, using a common language, etc.

Heck, the cover has a Kandinsky painting ... what more could you ask for?
paul wheaton
Trailboss

Joined: Dec 14, 1998
Posts: 20692
    ∞

Gregg,

Hav you looked at Jenny?

First, I think the term "DAO" should be avoided, if possible. I've simply encountered too many engineers that have different interpretations for what it means and it leads to confusion. Some think that a DAO has a one-to-one mapping with a table. Others think that a DAO speaks objects on one side and can work with many tables on the back side. I prefer TG: Martin Fowler's "Table Gateway Pattern". This is the DAO with the one-to-one mapping. Where I'm working now, we say "OPL" (Object Persistence Layer) to refer to a class that will persist your objects for you and may use many TG's under the covers.

Unlike Mr. Harkness, I prefer to use static methods for anything that does not make for an object (no state means no object). I think that it is important to provide the simplest possible API at each layer. I also think that factories are over used.

Much like Mr. Harkness, I am passionate about good unit testing complete with healthy mocking.

My solution is that a class provides static methods, but those methods will call an instance of an inner class called "Implementation". The unit test code will create a mock class that extends that "Implementation" and tells the class to be mocked to use the mock in place of the default implementation.

Jenny does this.

Production code now looks a bit like this:

String name = EmployeeTable.get( id ).getName();

Instead of

String name = EmployeeTable.getInstance().get( id ).getName();


permaculture Wood Burning Stoves 2.0 - 4-DVD set
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

Hav you looked at Jenny?

Yes I have. I played around with it probably 6 months ago. Now, if I understand Jenny correctly, I would use it *instead of* Hibernate, right? I'm not sure that I want to drop Hibernate right now.

Unlike Mr. Harkness, I prefer to use static methods for anything that does not make for an object (no state means no object). I think that it is important to provide the simplest possible API at each layer.

It's good to hear a different POV on the subject. Originally, all my DAO classes just had static methods.

My solution is that a class provides static methods, but those methods will call an instance of an inner class called "Implementation". The unit test code will create a mock class that extends that "Implementation" and tells the class to be mocked to use the mock in place of the default implementation.

Any chance you could post an example of a class like you are speaking of. I'm not sure I am completely understanding. Why would I provide an inner class called *Implementation* and not just provide the implementation in the parent class methods? An example class would probably clear that up.
Gregg Bolinger
GenRocket Founder
Ranch Hand

Joined: Jul 11, 2001
Posts: 15299
    
    6

Any chance you could post an example of a class like you are speaking of.

Nevermind, I am looking at the example source on the jenny web page.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Originally posted by Paul Wheaton:
I prefer TG: Martin Fowler's "Table Gateway Pattern". This is the DAO with the one-to-one mapping.
In my case, since some domain objects contain Collections (Sets actually) of related entities and aggregates, my DAOs don't have a one-to-one mapping to tables, but I still think either name is applicable. Whether it maps to one or multiple tables, it still provides access to the underlying data source.
Unlike Mr. Harkness, I prefer to use static methods for anything that does not make for an object (no state means no object).
Keep in mind that objects provide both state and behavior. Objects without state may still need to have their behavior overridden. Besides, the DAO does end up having state: a Hibernate SessionFactory.
My solution is that a class provides static methods, but those methods will call an instance of an inner class called "Implementation".
That's pretty cool. Am I correct that mocking requires CGLIB (in-place alteration of existing classes) due to the use of an inner class? Not a real problem as CGLIB is quite mature, but some people still have an aversion to it for various reasons.

The only advantage to using objects versuses your method of static methods that comes to mind -- and it's a stretch -- is that you are limited to a single implementation and DataSource at any one time. Using objects, you can create as many DAOs as necessary (for example, in a data-transfer application that requires your business logic be used instead of a simple import/export tool. I have needed to do this in the past, so I think it is a legitimate concern, but not exceedingly major.

Finally, since my business objects are wired up to their DAOs at startup (the DAOs are instance members of the BOs), the API looks no different from the static method API:Thanks for adding to the discussion! I certainly don't claim to have "the way," so it's good to see other options.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
I haven't looked at Jenny yet, but I thought of one other thing that could be a downside to static methods with an inner class: duplicate method declarations. I assume that for each method on the DAO you have an instance method on the inner class and a matching static method that delegates to it. Doesn't this make writing the DAOs somewhat cumbersome?

Anyway, I'll check out Jenny and correct my post if I find my assumption was faulty.
paul wheaton
Trailboss

Joined: Dec 14, 1998
Posts: 20692
    ∞

Jenny uses multiple data sources.

Sorry, I don't know what CGLIB is.

Jenny generates everything you need. Jenny essentially generates what many people call a "DAO". All OTR is done in Java as opposed to XML or javadoc.
David Harkness
Ranch Hand

Joined: Aug 07, 2003
Posts: 1646
Originally posted by Paul Wheaton:
Jenny uses multiple data sources.
Can it use multiple data sources for the same DAO at the same time? I don't mean a DAO that uses two data sources to do its work, I mean two of the same DAOs (UserDAO) that point to do different data sources. For example, how would a tool that copies users from one database to another use the singleton UserDAO against two DSes?
Sorry, I don't know what CGLIB is.
My bad, it often comes up when discussing mock objects, so I assumed you were familiar with it. CGLIB is a tool to modify class files at runtime. It is used frequently when you need to replace (with a mock) or augment (with AOP) a class instead of interface. When you have an interface, you can just generate a class that implements it, but when you have a class, you need to alter it in-place.
Jenny generates everything you need. Jenny essentially generates what many people call a "DAO".
Cool, that pretty much answers it for me. So with Jenny my point about duplicate methods is moot.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
 
subject: Data Access Objects: static methods