I'm attempting to retrofit Hibernate into our Database persisted Desktop application, with a Swing GUI.
I've been running into problems in a couple areas, particularly Connection and Session management. In the interest of keeping this post focused, I'll focus on what seems to be my stickiest problem: Sharing a single connection.
Our database server (FirstSQL) runs within the same virtual machine as the application, and only allows a single connection at any given time. Attempts to spawn further connections give exceptions.
Within a single thread, this isn't an issue. However, since this is a Swing application, there are a few threads being used, sometimes for background db access, sometimes to allow an interactive progress bar to be displayed, but there are cases where two threads may both be performing database access concurrently.
Since Sessions aren't threadsafe, I'm using the ThreadLocal Session pattern.
I'm also using the C3PO Connection proxy to allow preparedstatement caching.
Additionally, some legacy code needs direct access to the connection, since there are enough classes that hibernate must be eased in slowly while keeping the app functional.
Currently I'm passing the Connection to the SessionFactory.openSession() to prevent a second thread from freezing when it attempts to obtain a connection from the Session.
This seems like it would work but here's the bizarre problem I get, seemingly impossible:
The following code executes without error:
Code:
conn.prepareStatement("select * from book");
assert !conn.isClosed();
SwingUtilities.invokeAndWait(
new Runnable() {
public void run() {
try {
assert !conn.isClosed();
conn.prepareStatement("select * from book");
} catch (Exception e) {
throw new DAOException(e);
}
}
});
but the following code, differing only by the addition of the first three lines, throws an AssertionError
Code:
URL url = ClassLoader.getSystemResource("sb/data/dao/hibernate/hibernate.cfg.xml");
Configuration configuration = new Configuration().configure(url);
configuration.buildSessionFactory();
conn.prepareStatement("select * from book");
assert !conn.isClosed();
SwingUtilities.invokeAndWait(
new Runnable() {
public void run() {
try {
assert !conn.isClosed(); <-- ASSERTION ERROR HERE!!!
conn.prepareStatement("select * from book");
} catch (Exception e) {
throw new DAOException(e);
}
}
});
How is this possible? Note that everything works fine if the SessionFactory is not built. I've even made sure (stepping through hibernate source) that the SessionFactory is not using a C3PO connection. I can think of no reason why the conn would close itself just because it is within an invokeAndWait() method, and particularly not ONLY when i have also built a sessionfactory. It took me a full day to nail down this failure case from a much more complex scenario, and my frustration is nearing the point where i throw up my hands and going back to hand-coded persistence, which I dread.
I would pass this off as a java or c3po bug if it weren't for the fact that this only happens when the session factory is built, somehow it causes the connection to self destruct later on down the line.
HELP! I really want to use hibernate but this problem has me stumped after nearly three days of trying to make threads behave while sharing a single connection.