Search code examples
javaspringhibernatec3p0applicationcontext

Testing the database connection with spring and hibernate


I'm currently working on a java application. It's a standalone client with Spring and Hibernate. Also C3P0.

In the previous version we used a standard user(hardcoded in the configuration file) for the database connection but now we changed it so that every user has to provide his own credentials.

The beans with the code for the database are basically created on-demand.
I changed the XML-files and added a postprocessor which sets the credentials as well as some connection settings. It looks similar to this now:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();

configurer = new PropertyPlaceholderConfigurer();

// properties are retrieved from a private method
configurer.setProperties(getProperties());

context.addBeanFactoryPostProcessor(configurer);

context.setConfigLocations(new String[] { "first.xml","second.xml" });

context.refresh();  

return context.getBean("myClass", MyClass.class);

This all works as expected but now we reach the part where I'm currently stuck.

I want to provide a test functionality for the connection, so that the user can click a button and then is told if his credentials were accepted or not.
My first idea was to do a simple select on the database. Sifting through the logs however, I noticed that Spring tries to connect to the database during the refresh() (or rather the instantiation of the bean) anyway. I can see exceptions in the logs, for example:
java.sql.SQLException: Connections could not be acquired from the underlying database!
Unfortunately, Spring doesn't seem to actually care. The exceptions are logged away but refresh() finishes and is not throwing any exceptions because of this. I had hoped that I could simply catch the exception and then I would know that the connection failed.

I could just do the select as planned, but I want to limit the connection attempts as much as possible, because the database server will block the user after several attempts. Even permanently if there are to many attempts(already had some fun with that, before I changed the settings for the connection pool).

My searches regarding this problem came up with practically nothing. Is there a way to get the exception somehow? Or does Spring provide an API of sorts that would tell me about the connection error during the instantiation/refresh?

Failing that, any ideas for an alternative approach? Preferably one that needs only a single attempt to determine if a connection is possible.

Edit: For anyone interested: I went with the suggestion from Santosh and implemented a connection test in JDBC.
Unfortunately there seems to be no easy way to make use of the database errors/exceptions encountered during the bean instantiation.


Solution

    1. The kind of functionality you are looking for would be very tricky to accomplish using spring+hibernate.
    2. The connection properties are set at the session-factory level and if credentials are incorrect, the session-factory is not instantiated.
    3. Quoting @Bozo from his answer here.

      What you can do is extend LocalSessionFactoryBean and override the getObject() method, and make it return a proxy (via java.lang.reflect.Proxy or CGLIB / javassist), in case the sessionFactory is null. That way a SessionFactory will be injected. The proxy should hold a reference to a bare SessionFactory, which would initially be null. Whenever the proxy is asked to connect, if the sessionFacotry is still null, you call the buildSessionFactory() (of the LocalSessionFactoryBean) and delegate to it. Otherwise throw an exception. (Then of course map your new factory bean instead of the current)

    4. There is also a simple and rudimentary approach wherein before creating ClassPathXmlApplicationContext, simply try to obtain a connection using raw JDBC calls. If that succeed then proceed or else give use appropriate message.

    5. You can limit the connection attempts here as you are in full control.