Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vaadin and Hibernate - Close connection to database correctly

I'm currently experiencing an interesting problem.

My Situation:

  • I am currently developing a web service (I'm using VAADIN for programming with JAVA in eclipse)
  • My database behind is java derby
  • I am using hibernate for my database
  • I'm currently deploying it on Tomcat v7.0

My Problem:

  • When I change something in my code (doesn't matter what), the server should reload it without the need of being restarted - I guess that's the overall expected behaviour
  • The server reloads the application successfull, but if I try to click on something (so after the reloading), e.g. the login-Button, I get an error

Error Message:

Cause: org.hibernate.exception.GenericJDBCException: Could not open connection] with root cause ERROR XSDB6: Another instance of Derby may have already booted the database C:\HTML-Ausgabe\database\DocumentDB. at org.apache.derby.iapi.error.StandardException.newException(Unknown Source) ...

My Thoughts on this

It seems that somehow on the reloading process the connection/context to hibernate doesnt get destroyed/closed and so the error occures when the server tries to reconnect to the database

My Code

I have a class, called Hibernate Listener:

public class HibernateListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        HibernateUtil.getSessionFactory(); // Just call the static initializer of that class    
    }

    public void contextDestroyed(ServletContextEvent event) {
        HibernateUtil.getSessionFactory().close(); // Free all resources
    }
}

My hibernate.cfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.apache.derby.jdbc.EmbeddedDriver</property>
        <property name="hibernate.connection.url">jdbc:derby:C:\HTML-Ausgabe\database\DocumentDB;create=true</property>
        <property name="hibernate.dialect">org.hibernate.dialect.DerbyDialect</property>
        <property name="hibernate.current_session_context_class">thread</property>
        <property name="hibernate.hbm2ddl.auto">create-drop</property>
        <property name="hibernate.show_sql">true</property>

        <mapping class="view.model.database.User"/>
        <mapping class="view.model.database.Document"/>
        <mapping class="view.model.database.Version"/>
        <mapping class="view.model.database.VersionData"/>
    </session-factory>
</hibernate-configuration>

My (VAADIN) web.xml, in which I added a "listener" for the upper shown HibernateListener (check the text at listener ):

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Bachelorprojekt</display-name>
    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    <servlet>
        <servlet-name>Bachelorprojekt Application</servlet-name>
        <servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
        <init-param>
            <description>Vaadin application class to start</description>
            <param-name>application</param-name>
            <param-value>view.view.WebsiteFrame</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Bachelorprojekt Application</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>view.model.database.HibernateListener</listener-class>
    </listener>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

I did research, posted also on the hibernate forum (still without even a single answer :( ) and now did not find a matching theme on this website. So I hope I didn't do something wrong.

If anyone of you could help me somehow, I would be really happy. Currently I dont know what to change to stop this error happening. And, of course, I cant always restart the whole server later when my application is on the internet, if I change one line of code.

Thanks a lot for every answer and thought that you're sharing with me.

like image 667
Waylander Avatar asked Mar 26 '12 18:03

Waylander


People also ask

How can I close database connection in Hibernate?

You don't directly open or close database connections when using Hibernate, it will close them for you. You do however open and close its session factory and session objects.


2 Answers

I found the solution to my problem.

First of all, it was an apache derby problem, as I forced it to close with

public void contextDestroyed(ServletContextEvent event) {
    HibernateUtil.getSessionFactory().close(); // Free all resources
    try {
          DriverManager.getConnection("jdbc:derby:;shutdown=true");
    } catch (SQLException e) {}
    }
}

it worked fine for me.

Now I swichted my database vom apache derby to mysql and noticed that the problem, described in my question above, didn't occur anymore.

So, lesson learned: Don't use apache derby. I hope this helps someone else someday. Thanks a lot for your help.

like image 94
Waylander Avatar answered Oct 23 '22 04:10

Waylander


Quick and dirty solution: A quick and dirty temporary solution might just be to append ?restartApplication to everywhere your Vaadin application is linked.

Better solution: I recommend using the session-per-request pattern with Hibernate. By using Vaadin's transaction listener you can easily ensure that session is closed on each request without polluting our program code with extra logic.

You place these methods in your main application method and then execute attachVaadinTransactionListener() in your init() method. Link to detailed article on this below.

    private void attachVaadinTransactionListener() {
    getContext().addTransactionListener(new TransactionListener() {
        public void transactionEnd(Application application,
                Object transactionData) {
            // Transaction listener gets fired for all (Http) sessions
            // of Vaadin applications, checking to be this one.
            if (application == EnpApplication.this) {
                closeSession();
            }
        }         

        public void transactionStart(Application application,
                Object transactionData) {
        }
    });
}

private void closeSession() {
    Session sess = HibernateUtil.getSessionFactory().getCurrentSession();
    if (sess.getTransaction().isActive()) {         
        sess.getTransaction().commit();  

        if(sess.isOpen()) { sess.flush(); }
    }
    if(sess.isOpen()) {         
        sess.close();
    }
}

Hibernate with Vaadin

like image 37
anataliocs Avatar answered Oct 23 '22 03:10

anataliocs