Run your query through Hibernate, using the native query interface. Alternately, you can get the underlying JDBC connection from a Session object via Session.connection() ... though this won't work if you're using Hibernate via the JPA2 APIs.
Another option is to borrow connections from the connection pool while Hibernate isn't using them. If you're using C3P0, it provides an instance registry interface (sorry, I don't remember the class name) that lets you get the pool Hibernate created and use it.
Personally, I didn't want or need pooling for my simple J2SE app. I landed up writing a new Hibernate ConnectionProvider that manages a single JDBC connection for this purpose. It provides registration of instances so that I can get to the provider once Hibernate has created it, and provides a status listener interface as well. I've included it below in case it's something that you might find informative or be able to adapt to your purposes.
Code:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Properties;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.connection.ConnectionProvider;
import org.hibernate.cfg.Environment;
import org.hibernate.connection.ConnectionProviderFactory;
import org.hibernate.util.PropertiesHelper;
/**
* SingleConnectionProvider is a minimal Hibernate ConnectionProvider
* that manages a single JDBC connection obtained from the DriverManager.
*
* This bypasses Hibernate's obsession with connection pools, and lets us
* use our one JDBC connection in a normal J2SE app for whatever we need to,
* whether through Hibernate or via direct JDBC use.
*
* A listener interface is provided for observation of the
* SingleConnectionProvider's activities. This permits management of things like
* PostgreSQL Listen/Notify on a connection - when a connection breaks and a
* new one is re-created, we can re-listen on it when informed about the
* event by SingleConnectionProvider.
*
* SingleConnectionProvider also maintains a registry of instances of its self.
* Hibernate doesn't provide any direct way to get at its connection providers
* or the resources they use (is it jealous?) so we need to work around it.
*
* SingleConnectionProvider looks like a connection pool to Hibernate and
* other users, but always returns the same connection. If the connection
* is busy, getConnection() will block until it is returned to the provider.
*
* @author Craig Ringer <craig@postnewspapers.com.au>
*/
public class SinglePgConnectionProvider implements ConnectionProvider{
public enum ConnectionEvent {
/**
* new connection has been created. The listener
* may at this point modify the connection if it needs to - for
* example, adding PostgreSQL notification listeners.
*/
CREATED,
/**
* Called when a connection has been closed. The passed connection
* is already closed and may be invalid.
*/
CLOSED,
/**
* A connection is about to be checked out from the pool. It is
* not yet busy and may safely be used for JDBC operations, though
* those will of course delay the request.
*
* It is really, really important not to leave the connection
* unclean in any way. Leaving a transaction open can have nasty
* consequences.
*/
ABOUT_TO_BE_CHECKED_OUT,
/**
* Somebody has checked out `conn' and it is in use. It is not safe
* to use `conn' for JDBC operations.
*/
CHECKED_OUT,
/**
* Somebody has returned `conn' to the pool. It might be
* closed and/or broken.
*/
RETURNED;
}
/**
* Observers interested in the connection pool's activities may
* implement this method.
*/
public interface SinglePgConnectionProviderListener {
/**
* Called when something happens on the connection. Check `evt' for what.
* @param connInfo Affected connection details
* @param evt Event that happened
*/
void connectionEvent(ConnInfo connInfo, ConnectionEvent evt);
}
/**
* simple structure containing connection and associated pid,
* to be used with getConnectionEvenIfBusy().
*/
public class ConnInfo {
public ConnInfo(Connection conn, long pid) {
assert(conn != null);
assert(pid != -1);
this.conn = conn;
this.conn_backend_pid = pid;
}
public final Connection conn;
public final long conn_backend_pid;
}
private static final List<SinglePgConnectionProvider> providers = new ArrayList<SinglePgConnectionProvider>(1);
private final Logger log = Logger.getLogger(SinglePgConnectionProvider.class);
private ConnInfo connInfo;
private boolean conn_busy = false;
private boolean mayBeSSL;
private boolean autoCommit;
private Integer isolation;
private String url;
private Properties connectionProps;
private final Set<SinglePgConnectionProviderListener> listeners = new HashSet<SinglePgConnectionProviderListener>(1);
public SinglePgConnectionProvider() {
providers.add(this);
}
public void removeSinglePgConnectionProviderListener(SinglePgConnectionProviderListener l) {
listeners.remove(l);
}
public void addSinglePgConnectionProviderListener(SinglePgConnectionProviderListener l) {
listeners.add(l);
}
@Override
public void configure(Properties props) throws HibernateException {
log.debug("Configuring SinglePgConnectionProvider");
autoCommit = PropertiesHelper.getBoolean(Environment.AUTOCOMMIT, props);
isolation = PropertiesHelper.getInteger(Environment.ISOLATION, props);
url = props.getProperty( Environment.URL );
connectionProps = ConnectionProviderFactory.getConnectionProperties( props );
// Quick and dirty check to see if the connection *might* be an SSL one
// We need to know this because listen/notify behaviour changes on ssl connections.
mayBeSSL = (connectionProps.containsKey("ssl")) || url.contains("ssl=");
connInfo = null;
String driverClass = props.getProperty(Environment.DRIVER);
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
throw new HibernateException("Could not load JDBC driver " + driverClass, e);
}
log.info("Configured SinglePgConnectionProvider");
}
@Override
public synchronized Connection getConnection() throws SQLException {
while (conn_busy) {
// Wait for the connection to be freed
try {
wait();
} catch (InterruptedException e) {
// Re-check busy and re-wait if necessary
}
}
clearConnectionIfIsClosed();
if (connInfo == null) {
createConnection();
}
notifyConnectionEvent(ConnectionEvent.ABOUT_TO_BE_CHECKED_OUT);
if (isolation!=null) {
connInfo.conn.setTransactionIsolation( isolation );
}
if ( connInfo.conn.getAutoCommit()!= autoCommit ) {
connInfo.conn.setAutoCommit(autoCommit);
}
conn_busy = true;
notifyConnectionEvent(ConnectionEvent.CHECKED_OUT);
return connInfo.conn;
}
/**
* Returns the PostgreSQL JDBC connection even if it's checked out by
* somebody else.
*
* While the JDBC connection is thread-safe, it is still really <i>not</i>
* safe to do work with it, as your work may interleave with somebody
* else's transaction and get lost if they rollback(), may break someone
* else's transaction if it causes an error, etc.
*
* This method exists primarily for listen/notify polling by PgNotificationPoller.
*
* @return A ConnInfo object containing the connection and its pid
*/
// Intentionally package-private
ConnInfo getConnectionEvenIfBusy() {
return connInfo;
}
@Override
public synchronized void closeConnection(Connection conn) throws SQLException {
log.debug("returned connection " + conn);
if (connInfo.conn != conn) {
throw new HibernateException("Hibernate returned a different connection to the pool than the one we gave it!");
}
notifyConnectionEvent((ConnectionEvent.RETURNED));
clearConnectionIfIsClosed();
conn_busy = false;
notifyAll();
}
@Override
public void close() throws HibernateException {
log.info("Closing SinglePgConnectionProvider");
clearConnection();
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
/**
* @return true if the connection *might* be using SSL. Stable over life of SinglePgConnectionProvider.
*/
public boolean getMyBeSSL() {
return mayBeSSL;
}
private void createConnection() throws SQLException {
assert(connInfo == null);
log.info("Creating new connection for pool");
Connection newConn;
try {
newConn = DriverManager.getConnection(url, connectionProps);
} catch (SQLException e) {
log.error("Unable to create connection", e);
throw e;
}
long conn_backend_pid = -1;
Statement stmt = newConn.createStatement();
try {
stmt.executeQuery("SELECT pg_backend_pid FROM pg_catalog.pg_backend_pid();");
ResultSet rs = stmt.getResultSet();
rs.next();
conn_backend_pid = rs.getLong(1);
rs.close();
} finally {
stmt.close();
}
connInfo = new ConnInfo(newConn, conn_backend_pid);
log.info("Pooled connection created, backend pid is " + conn_backend_pid);
conn_busy = false;
notifyConnectionEvent(ConnectionEvent.CREATED);
}
private void clearConnection() {
if (conn_busy) {
throw new IllegalStateException("clearConnection() called when connection busy");
}
if (connInfo != null) {
log.info("Clearing pooled connection");
try {
connInfo.conn.close();
} catch (SQLException e) {
log.warn("Conn close failed: ", e);
}
}
notifyConnectionEvent(ConnectionEvent.CLOSED);
connInfo = null;
}
private void clearConnectionIfIsClosed() {
if (connInfo != null) {
try {
if (connInfo.conn.isClosed()) {
log.info("Clearing connection that was closed in the pool");
clearConnection();
}
} catch (SQLException e) {
log.info("Clearing connection that threw on isClosed()", e);
clearConnection();
}
}
}
/**
* Obtain the connection properties. Useful for telling the difference between
* different provider instances.
*
* Do <i>not</i> call closeConnection(...) with this connection.
*
* @return JDBC/DriverManager connection properties for this provider
*/
public Properties getConnectionProperties() {
return connectionProps;
}
@Override
protected void finalize() {
providers.remove(this);
clearConnectionIfIsClosed();
}
private void notifyConnectionEvent(ConnectionEvent evt) {
for (SinglePgConnectionProviderListener l : listeners) {
try {
l.connectionEvent(connInfo, evt);
} catch (Throwable e) {
log.error("SinglePgConnectionProviderListener.connectionEvent " + l + " threw", e);
}
}
}
/**
* @return a read-only view of the set of providers currently registered
* in the system.
*/
public static List<SinglePgConnectionProvider> getProviders() {
return Collections.unmodifiableList(providers);
}
}