This article is about some implications of how you implement the Data Access Objects pattern on your Java applications.
This article uses the terms “connection” and “database connection” to refer to a link to a data source. No matter the way this link is stablished. This is not about JDBC or anything else. This article is not targeting a specific technology of database connectivity nor a method of data persistence.
At some point, this article refers to Dependency Injection (DI), considering the CDI API.
One connection per operation – implications
It’s a common practice among starters to create DAO Implementations that open a new database connection on each operation method without the knowledge of the implications it brings to their applications. I’m talking about a DAO Implementation like this one:
What is wrong with this? First, You are adding the overhead of opening a new db connection to each of your DAO Methods. Invoking any of the methods will open a new database connection even on the same DAO instance. The second problem is: How are you going to group DAO Operations in a single transaction?
The one-connection-per-operation approach wont help you on this. It will actually make it hard to implement this because your methods are not sharing the connection.
But this is not bad at all. The good thing here is that you will never have a connection leak on this case. The second good thing is that you DAO is naturally Thread-Safe.
Premature Connection issue (DAOs with DI)
Some people are not adepts of the one-connection-per-operation approach and prefer to open a database connection right on the DAO constructor, like this:
Note that the constructor of StudentDaoImpl connects to the database. Is it bad? Its not bad until you start using DI (Dependency injection), then it becomes. Lets see how it works without DI:
When you are not using DI, you instantiate the DAO Implementations classes by yourself while when you are using DI, the DI container does it for you. There few bad things that may happen if you keep connecting to the database on DAO Implementations constructor when introducing DI.
The Data Access beans are intended to be injected into beans of the Business Layer.
A single bean of the business layer, may inject into itself more than one DAO instance.
From now on, lets assume there three DAO Implementations : StudentDAOImpl, CourseDAOImpl and StudentSubscriptionsDAOImpl correspondent to three DAO Interfaces: StudentDAO, CourseDAO, StudentSubscriptionsDAO.
Each of the DAO implementations opens a new connection to the database on its constructor.
In order to understand the Premature connection issue its necessary to emulate a scenario with a Business bean that injects multiple DAO instances into itself. Check out the following example:
The Subscriptions bean injects into itself 3 DAO instances and it has two business methods: newSubscription and getStudentCourse. The first business method uses 2 of the 3 DAO instances (studentDao and courseDao) and the second business method uses a single DAO Instance (studentSubsDao).
Imagine a scenario where we have a Servlet that injects into itself an instance of the Subscriptions bean. The subscriptions bean is RequestScoped, meaning that, a new instance of the Subscriptions bean will be created for each new HTTP Request :
By the time the Subscriptions bean instance get injected into the Servlet, three connections to the database will be opened. Why? Because the CDI container will instantiate the three DAO Implementations correspondent to StudentDAO, CourseDAO and StudentSubscriptionsDAO and inject them into the Subscriptions bean instance.
Honestly, you don’t need three database connections to handle a single client request, do you? Imagine if you simply want to get the course to which a student subscribed (getStudentCourse). Three connections is a waste of resources.
The worst thing is that you will have connection leaks. Imagine if a user performs an HTTP Request simply to get the course to which a student subscribed: The getStudentCource method of the Subscriptions bean, only uses the studentSubsDao, that’s why it only closes the connection of that single DAO. The other two connections (opened automatically for studentSubsDao and courseDao) will remain open. Soon or later you will end up facing the “Too Many connections” error.
The first attempt of fixing the Premature connection issue
The worst thing you can do is to close all connections on each business method:
Do not engage on this approach. It’s a suicide mission.
You will be creating another problem here. If you do this. It will be impossible to invoke the two business methods (getStudentCourse and newSubscription ) sequentially from the TestServlet, no matter the order of invocation. I will say it again: If you close the connection of all the DAO instances on each of the business methods, it will be impossible to invoke both business methods on the same Http Request:
This code will fail on the line tagged as “second line”. Why? Because you will be trying to use DAO instances with closed connections. The line tagged as “first line” closes the connection of each DAO instance of the Subscriptions bean instance declared as subs.
The definitive solution
How do you get rid of this issue? Avoid connecting to the database on the DAO Implementations constructors. You might be like “should I create a public method to connect to the database?”. If that though passed through your mind. I will clarify your ideas: Your don’t have to create a public method to connect to the database.
All you have to do is check if a connection already exists before you perform any operations and open a new connection if no connection exists. That would be a smart change.
Check closed state
You should provide a way of checking if a DAO instance is closed (the internal datasource connection) in order to allow your business layer Beans to close it at any cost and avoid connections leaks.
Auto-close
Java 7 came out with a new feature that I personally believe was a smart update. The feature is designated try-with-resource statement . What is it?
This code:
Can now be written this way:
You don’t have to invoke the close() method on the finally block manually. It will be invoked automatically for you.
What are the requirements for your DAO Implementations to be auto-closed?
They must implement the interface java.lang.AutoCloseable. Every Type that extends or implements java.lang.AutoCloseable can be used on a try-with-resource statement. This can simplify the use of your DAOs. No more explicit close().
What about the transaction problem we talked about on the one-connection-per-operation topic? Stay tune. I will be writing about it soon. I will also be writing a DI introduction article using CDI API.
It’s always a pleasure.
🙂







Comentários Recentes