Connection pooling uses the Java container to maintain the connection to the database. How the connection pooling is implemented is somewhat different from server to server.
You will have to create a data source and register the driver in the container and tell the container how many connections to maintain. Then register the data source through JNDI.
In your application code, you have to look up the resource through JNDI, and obtain a connection from the container as a data source. From that point on, it works just like you registered the database driver and created the connection yourself.
While not recommended, it's also quite possible to write your own. You can make a good generic object pool with a BlockingQueue. For a Connection pool you'd want to override Connection to put itself back in the pool when you call close(). My team uses a home-made pool that does that plus some neat automatic reconnect stuff that wasn't readily available years ago. We've just started replacing it with standard data sources and UDB features.
But back to the whole reason for all this complexity ... It's much faster to get a connection out of a pool than it is to open a new one. It's even faster to put one back instead of closing it. And if you were around for the good old Client-Server days, a company might have thousands of users with VB apps connected to a database, which puts a big load on the database. Now in multi-tier systems an application server can keep a smaller number of connections, just enough to handle concurrent requests that really run at the same time. The reduced number of connections makes life better for the database.
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi