One suggestion to prevent and report the database connection leaks:
First find out the scope of each connection.
Example, for many web applications a connection is needed in the scope of a request.
With the scopes defined all you need to do is to close the connection in a deterministic way by doing it at the end of the scope life cycle.
One way to of asserting that a database connection is always closed in a web application is to create a servlet filter that will get the connection when a request comes in and close the connection when the response is sent. The connection can be passed from the filter to other objects by putting it in a ThreadLocal variable.
Another example of scope is when a connection is needed per transaction. You may want to use the Execute Around Method pattern to get the connection before the scope begin and close it at the end in a deterministic way.
If you implement any of these ideas you may even log which connections were not closed before you close it to help identify the leak.
Good luck, I hope this helps, please let me know otherwise.
Update:
I just solved a database connection leak in legacy code by adding debugging parameters to the database connection pool implementation apache DBCP.
Even if you don't want to use DBCP in production you could still set it up in test just to detect the exact line code that borrowed the unclosed connection.
In my environment I used tomcat with the JNDI datasource config like so :
<Resource auth="Container"
name="jdbc/APP_NAME"
username="user"
password="password"
url="jdbc:oracle:thin:@server.domain:1521:development"
type="javax.sql.DataSource"
driverClassName="oracle.jdbc.driver.OracleDriver"
maxIdle="10"
maxWait="5000"
maxActive="10"
validationQuery="select 1 from dual"
validationInterval="30000"
testOnBorrow="true"
testOnReturn="false"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="5000"
numTestsPerEvictionRun="3"
minEvictableIdleTimeMillis="30000"
<!-- These 3 settings saved me hours of headache -->
logAbandoned="true" <!-- Will report the stacktrace of the faulty code -->
removeAbandoned="true" <!-- Will remedy the connection starvation while leaky code is not fixed-->
removeAbandonedTimeout="60"<!-- Interval for fixing connection starvation while leaky code is not fixed-->
/>
See : Apache DBCP configuration