JSF ページで複数のトランザクションを実行しようとすると、次のエラーが発生します。
A potential connection leak detected for connection pool MSSQL. The stack trace of the thread is provided below :
com.sun.enterprise.resource.pool.ConnectionPool.setResourceStateToBusy(ConnectionPool.java:324)
com.sun.enterprise.resource.pool.ConnectionPool.getResourceFromPool(ConnectionPool.java:758)
com.sun.enterprise.resource.pool.ConnectionPool.getUnenlistedResource(ConnectionPool.java:632)
com.sun.enterprise.resource.pool.AssocWithThreadResourcePool.getUnenlistedResource(AssocWithThreadResourcePool.java:196)
com.sun.enterprise.resource.pool.ConnectionPool.internalGetResource(ConnectionPool.java:526)
com.sun.enterprise.resource.pool.ConnectionPool.getResource(ConnectionPool.java:381)
com.sun.enterprise.resource.pool.PoolManagerImpl.getResourceFromPool(PoolManagerImpl.java:245)
com.sun.enterprise.resource.pool.PoolManagerImpl.getResource(PoolManagerImpl.java:170)
com.sun.enterprise.connectors.ConnectionManagerImpl.getResource(ConnectionManagerImpl.java:338)
com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:301)
com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:190)
com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:160)
com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:113)
cl.codesin.colegios.util.persistencia.DAOManejador.abrir(DAOManejador.java:126)
貼り付けた最後の行に注意してください。
cl.codesin.colegios.util.persistencia.DAOManejador.abrir(DAOManejador.java:126)
abrir
次のことを行います。
public void abrir() throws SQLException {
try
{
if(this.con==null || this.con.isClosed())
this.con = fuenteDatos.getConnection();
}
catch(SQLException e)
{
throw e;
}
}
これはシングルトン DAO マネージャーで次のように機能します。DAO マネージャーは各 DAO の 1 つのインスタンスを持ち、すべての DAO が共有する単一の接続を管理します。DAO が要求されると、次の処理が行われます。
public DAORegion getDAOregion() throws SQLException {
try
{
if(con == null) //con is the connection the DAO manager uses
{
this.abrir();
}
}
catch(SQLException e)
{
throw e;
}
if(this.DAOregion==null)
{
this.DAOregion = new DAORegion(this.con);
}
return DAOregion;
}
接続を閉じるとき、マネージャーはcon.close()
他に何もせずに呼び出すだけです。
ちなみに、私は JDBC を使用しているため、persistence.xml はありません。
私は何を間違っていますか?よろしくお願いします。
編集:Glassfishサーバーからのリーク検出を無効にすることで、例外を回避できましたが、「接続が閉じられました」というエラーが引き続き発生します。最悪なのは、エラーがスローされている場所が正確にわからないことです。
編集 2: DAO マネージャーを再度変更しました。これが実装です。
public class DAOManejador {
public static DAOManejador getInstancia() {
return DAOManejadorSingleton.INSTANCIA;
}
//This is just a sample, every getDAOXXX works the same.
public DAOUsuario getDAOusuario() throws SQLException {
try
{
if(con == null)
{
this.abrir();
}
}
catch(SQLException e)
{
throw e;
}
if(this.DAOusuario==null)
{
this.DAOusuario = new DAOUsuario(this.con, this.stmt, this.res);
}
return DAOusuario;
}
public void abrir() throws SQLException {
try
{
if(this.con==null || this.con.isClosed())
this.con = fuenteDatos.getConnection();
}
catch(SQLException e)
{
throw e;
}
}
public void iniciaTransaccion() throws SQLException {
try
{
con.setAutoCommit(false);
}
catch(SQLException e)
{
throw e;
}
}
public void cierraTransaccion() throws SQLException {
try
{
con.setAutoCommit(true);
}
catch(SQLException e)
{
throw e;
}
}
public void comprometer() throws SQLException {
try
{
con.commit();
}
catch(SQLException e)
{
throw e;
}
}
public void deshacer() throws SQLException {
try
{
con.rollback();
}
catch(SQLException e)
{
throw e;
}
}
public void cerrar() throws SQLException {
try
{
if(this.stmt!=null && !this.stmt.isClosed())
stmt.close();
if(this.res!=null && !this.res.isClosed())
this.res.close();
if(this.con!=null && !this.con.isClosed())
con.close();
}
catch(SQLException e)
{
throw e;
}
}
public void comprometerYTerminarTransaccion() throws SQLException {
try
{
this.comprometer();
this.cierraTransaccion();
}
catch(SQLException e)
{
throw e;
}
}
public void comprometerYCerrarConexion() throws SQLException {
try
{
this.comprometer();
this.cierraTransaccion();
this.cerrar();
}
catch(SQLException e)
{
throw e;
}
}
//Protegidos
@Override
protected void finalize() throws SQLException, Throwable
{
try
{
this.cerrar();
}
finally
{
super.finalize();
}
}
//Private
private DataSource fuenteDatos;
private Connection con = null;
private PreparedStatement stmt = null;
private ResultSet res = null;
private DAOUsuario DAOusuario = null;
private DAORegion DAOregion = null;
private DAOProvincia DAOprovincia = null;
private DAOComuna DAOcomuna = null;
private DAOColegio DAOcolegio = null;
private DAOManejador() throws Exception {
try
{
InitialContext ctx = new InitialContext();
this.fuenteDatos = (DataSource)ctx.lookup("jndi/MSSQL");
}
catch(Exception e){ throw e; }
}
private static class DAOManejadorSingleton {
public static final DAOManejador INSTANCIA;
static
{
DAOManejador dm;
try
{
dm = new DAOManejador();
}
catch(Exception e)
{ dm=null; }
INSTANCIA = dm;
}
}
}
ここで行ったことは、すべての DAO に単一のアクセス ポイントを提供することです。DAO がステートメントまたはリソースを使用する場合、それらはすべて同じものを使用します。もう一度開く必要がある場合、システムは次のことを行います。
public abstract class DAOGenerico<T> {
//Protected
protected final String nombreTabla;
protected Connection con;
protected PreparedStatement stmt;
protected ResultSet res;
protected DAOGenerico(Connection con, PreparedStatement stmt, ResultSet res, String nombreTabla) {
this.nombreTabla = nombreTabla;
this.con = con;
this.stmt = stmt;
this.res = res;
}
//Prepares a query
protected final void prepararConsulta(String query) throws SQLException
{
try
{
if(this.stmt!=null && !this.stmt.isClosed())
this.stmt.close();
this.stmt = this.con.prepareStatement(query);
}
catch(SQLException e){ throw e; }
}
//Gets a ResultSet
protected final void obtenerResultados() throws SQLException {
try
{
if(this.res!=null && !this.res.isClosed())
this.res.close();
this.res = this.stmt.executeQuery();
}
catch(SQLException e){ throw e; }
}
}
そして、それはまだ機能しません。