Pool de conexão Tomcat

3 respostas
D

Boa tarde galera…

é o seguinte, tenho um programa aki rodando no tomcat 4.1.24 que utiliza o pool de conexões de conexões gerenciado pelo próprio servidor. O que acontece é que o servidor tem aberto uma conexão para cada usuário e após algum tempo de uso o programa não consegue mais obter conexões e trava. Alguém tem alguma idéia??

Abaixo segue as configurações e o código fonte das classes que estou utilizando:

##Configuração do server.xml##

<Context path="MyApp" docBase="C:\\MyApp" debug="5" reloadable="true" crossContext="true" charsetMapperClass="org.apache.catalina.util.CharsetMapper">
            <Logger className="org.apache.catalina.logger.FileLogger" prefix="localhost_myapp_log." suffix=".txt" timestamp="true"/>

            <Resource name="jdbc/mydb" auth="Container" type="javax.sql.DataSource"/> 

            <ResourceParams name="jdbc/mydb">
              <parameter>
                <name>factory</name>
                <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
              </parameter>
              <parameter>
                <name>driverClassName</name>
                <value>org.postgresql.Driver</value>
              </parameter>
              <parameter>
                <name>url</name>
                <value>jdbc:postgresql://servidor/mydb</value>
              </parameter>
              <parameter>
                <name>username</name>
                <value>user</value>
              </parameter>
              <parameter>
                <name>password</name>
                <value>passwd</value>
              </parameter>
              <parameter>
                <name>maxActive</name>
                <value>1</value>
              </parameter>
              <parameter>
                <name>maxIdle</name>
                <value>0</value>
              </parameter>
              <parameter>
                <name>maxWait</name>
                <value>5000</value>
              </parameter>
              <parameter>
                <name>removeAbandoned</name>
                <value>true</value>
              </parameter>
              <parameter>
                <name>removeAbandonedTimeout</name>
                <value>20</value>
              </parameter>
              <parameter>
                <name>logAbandoned</name>
                <value>true</value>
              </parameter>
            </ResourceParams>
        </Context>

##Classe que retorna as conexões do pool##

package myapp.sql;

import javax.sql.DataSource;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * Classe que implementa a tecnologia JNDI para acesso ao banco de dados. Esta
 * tecnologia também oferece suporte ao Pool de conexão, controlada pelo
 * WebServer( Tomcat ).
 * 
 * @author Diego R. Drumond
 * @version 1.0 13.08.2004
 */
public class DataSourceConnection
{
	/**
	 * String para recuperar o objeto via JNDI
	 */
	public static final String JNDI_URL = "java:/comp/env/jdbc/myapp";
	
	/**
	 * 
	 */
	private String JNDI_JDBC = null;

	/**
	 * Retorna um DataSource com a conexão com o banco de dados feita através de
	 * JNDI.
	 */
	protected DataSource ds = null;

	/**
	 * Retorna contexto da aplicação que contém o JNDI que será utilizado para
	 * conexão com o banco de dados.
	 */
	protected InitialContext ic = null;

	public DataSourceConnection(  ) throws NamingException
	{
		this.ic = new InitialContext( );
		this.ds = ( DataSource )ic.lookup( adi.componentes.sql.DataSourceConnection.JNDI_URL );
	}

	/**
	 * Método que retorna uma conexão com o banco de dados. Caso não exista mais
	 * nenhuma conexão a ser aberta, o método aguarda a liberação de uma
	 * conexão.
	 */
	public Connection getConexao( ) throws NamingException, SQLException
	{
		Connection con = null;
		if( ds == null || ic == null )
		{
			ic = new InitialContext( );
			ds = ( DataSource )ic.lookup( adi.componentes.sql.DataSourceConnection.JNDI_URL );
		}
		con = ds.getConnection( );
		con.setTransactionIsolation( java.sql.Connection.TRANSACTION_READ_COMMITTED );

		return con;
	}

	/**
	 * Retorna URL do JNDI que está sendo utilizado.
	 */
	public String getJNDI_URL( )
	{
		return DataSourceConnection.JNDI_URL;
	}
}

##Quando o usuário acessa o sistema, uma instância deste objeto é criada e inserida à sessão do mesmo.##

package myapp.sql;

import myapp.erros.GeneralException;
import myapp.log.LogDB;
import myapp.log.LogException;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.io.PrintWriter;

import javax.naming.NamingException;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Classe utilizada na manipulação de dados no banco de dados. Possui métodos de
 * abertura e fechamento de conexões, além de métodos para execução de comandos
 * SQL.
 *
 * @author Diego R. Drumond
 * @version 1.0 13.08.2004
 */
public class DBConnection
{
	/**
	 * Conexão retornada pela classe DataSourceConnection
	 */
	private Connection con = null;

	/**
	 * Efetua conexão com o banco dados, verficando se existe alguma conexão
	 * disponível.
	 */
	protected DataSourceConnection dsc = null;

	/**
	 * Objeto utilizado para fazer redirecionamento do usuário
	 */
	private HttpServletResponse response = null;

	/**
	 * Sessão atual do usuário.
	 */
	protected HttpSession session = null;

	/**
	 * Faz log de acesso ao banco de dados.
	 */
	protected LogDB log = null;

	/**
	 * Contexto da aplicação.
	 */
	protected ServletContext application = null;

	/**
	 * Objeto java.sql.Statement para enviar comandos ao banco de dados.
	 */
	private Statement stmt = null;

	/**
	 * Erro ocorrido durante a execução da classe.
	 */
	private String erro = null;

	/**
	 * Construtor
	 */
	public DBConnection( )
	{
		log = new LogDB( );
	}

	public DBConnection( Connection con, Statement stmt, DataSourceConnection dsc, LogDB log, ServletContext application, HttpSession session, String erro )
	{
		this.con         = con;
		this.stmt        = stmt;
		this.dsc         = dsc;
		this.log         = log;
		this.application = application;
		this.session     = session;
		this.erro        = erro;
	}

	/**
	 * Define se será usado controle de transação.
	 */
	public void setAutoCommit( boolean transaction ) throws Exception
	{
		try
		{
			if( con != null )
			{
				con.setAutoCommit( transaction );
			}
		}
		catch( SQLException e )
		{
			throw trataErro( "setAutoCommit(boolean transaction)", new GeneralException( e ) );
		}
	}

	/**
	 * Define contexto da aplicação. Obs.: O contexto deve ser definido antes da
	 * sessão.
	 *
	 * @param context Objeto application do JSP.
	 */
	public void setContext( ServletContext context )
	{
		this.application = context;
		log.setContext( context );
	}

	/**
	 * Retorna uma String contendo uma mensagem de erro retornado pelo SGDB
	 * formatada. Este solicita o código da mensagem de erro ao método
	 * <code>getCodErro</code>. Depois busca no web.xml a mensagem
	 * correspondente ao código obtido.
	 */
	public String getMsgErro( )
	{
		String err = this.erro;
		this.erro = null;

		return err;
	}

	/**
	 * Define response.
	 *
	 * @param response Objeto response do JSP
	 */
	public void setResponse( HttpServletResponse response )
	{
		this.response = response;
	}

	/**
	 * Define a sessão como a do usuário atual.
	 *
	 * @param session Objeto session do JSP.
	 */
	public void setSessao( HttpSession session )
	{
		this.session = session;
		log.setSessao( session );
		log.setJDBC( null );
		log.setURL( null );
	}

	/**
	 * Abre uma conexão com o banco de dados. A classe DataSourceConnection
	 * busca uma conexão não utilizada e retorna um objeto do tipo 'Connection'
	 * que é usado pela classe para execução dos SQL's.
	 *
	 * @param transaction Define se será feito controle de transação.
	 * @return True se uma conexão com o banco de dados for estabelecida.
	 */
	public boolean abreConexao( boolean transaction ) throws Exception
	{
		//caso a sessão não tenha sido definida retorna erro.
		if( ( this.session == null ) || ( this.application == null ) )
		{
			//trataErro( "abreConexao(boolean transaction)", new Exception( "Verifique se a sessão e o contexto foram definidos e se nenhum dos valores é [null]." ) );

			return false;
		}

		//	
		if( this.dsc == null )
			throw trataErro( "abreConexao(boolean transaction)", new Exception( "Verifique a chamada ao método 'start'." ) );

		try
		{
			//verifica se já existe uma conexão.
			if( con == null )
				con = dsc.getConexao( );
			//evita abrir outra conexão caso já exista uma ativa.
			else if( con.isClosed( ) )
				con = dsc.getConexao( );

			con.setAutoCommit( !transaction );
			stmt = con.createStatement( );

			DatabaseMetaData dbmd = con.getMetaData( );
			log.setJDBC( dbmd.getDriverName( ) + ", " + dbmd.getDriverVersion( ) );
		}
		catch( SQLException e )
		{
			throw trataErro( "abreConexao(boolean transaction)", new GeneralException( e ) );
		}
		catch( NamingException e )
		{
			String[] vars = 
			{
				adi.componentes.sql.DataSourceConnection.JNDI_URL )
			};
			throw trataErro( "setSessao(HttpSession session)", new GeneralException( e, vars ) );
		}

		System.out.println( "aberta - " + this.con );
		return true;
	}

	/**
	 * Executa comandos SQL.
	 *
	 * @return True se o comando for executado corretamente.
	 */
	public boolean executa( String sql ) throws Exception
	{
		if( !abreConexao( true ) )
			return false;

		try
		{
			stmt.execute( sql );
		}
		catch( SQLException e )
		{
			log.setSQL( sql );

			String[] vars = 
			{
				sql, 
				""
			};
			throw trataErro( "executa(String sql)", new GeneralException( e, vars ) );
		}

		return true;
	}

	/**
	 * Executa um comando SQL e retorna um ResultSet com os dados retornados
	 * pelo banco.
	 *
	 * @param sql Comando SQL a ser executado.
	 * @return Instância da classe ResultSet com os dados retornados pela
	 *         execução da Query.
	 */
	public ResultSet executaQuery( String sql ) throws Exception
	{
		ResultSet rs = null;

		if( !abreConexao( true ) )
			return rs;

		try
		{
			rs = stmt.executeQuery( sql );
		}
		catch( SQLException e )
		{
			log.setSQL( sql );

			String[] vars = 
			{
				sql, 
				""
			};
			throw trataErro( "executaQuery(String sql)", new GeneralException( e, vars ) );
		}

		return rs;
	}

	/**
	 * Executa SQL's do tipo INSERT, UPDATE, DELETE.
	 *
	 * @param sql Comando SQL a ser executado.
	 * @return Número de colunas afetados pela execução do comando.
	 */
	public int executaUpdate( String sql ) throws Exception
	{
		int rows = -1;

		if( !abreConexao( true ) )
			return rows;

		try
		{
			rows = stmt.executeUpdate( sql );
		}
		catch( SQLException e )
		{
			log.setSQL( sql );

			String[] vars = 
			{
				sql, 
				""
			};
			throw trataErro( "executaUpdate(String sql)", new GeneralException( e, vars ) );
		}

		return rows;
	}

	/**
	 * Encerra a conexão com o banco de dados.
	 *
	 * @param commit define se será feito commit ou rollback. True = commit.
	 * @return Retorna True se a conexão com o banco de dados for encerrada.
	 */
	public boolean fechaConexao( boolean commit )
	{
		System.out.println( "fechando - " + con );

		boolean closed = true;

		try
		{
			if( con.isClosed( ) )
			{
				con = null;
				return closed;
			}
		}
		catch( SQLException e )
		{
			con = null;
			return !closed;
		}
		catch( NullPointerException e )
		{
			con = null;
			return closed;
		}

		try
		{
			//verifica se é feito controle de transação.
			if( !con.getAutoCommit( ) )
			{
				if( commit )
					con.commit( );
				else
					con.rollback( );
			}

			stmt.close( );
			con.close( );
			stmt = null;
			con = null;
		}
		catch( SQLException e )
		{
			con = null;
			System.out.println( trataErro( "fechaConexao(boolean commit)", new GeneralException( e ) ) );
		}
		finally
		{
			if( stmt != null )
			{
				try
				{
					stmt.close( );
				}
				catch( SQLException e ) { }

				stmt = null;
			}

			if( con != null )
			{
				try
				{
					con.close();
				}
				catch (SQLException e) { }

				con = null;
			}
		}

		System.out.println( "fechada!" );

		return closed;
	}

	/**
	 * Cria um objeto <code>java.sql.PreparedStatement</code> para enviar
	 * comandos SQL parametrizados para o banco de dados.
	 */
	public PreparedStatement preparaSQL( String sql ) throws Exception
	{
		PreparedStatement ps = null;

		if( !abreConexao( true ) )
			return ps;

		try
		{
			ps = con.prepareStatement( sql );
		}
		catch( SQLException e )
		{
			log.setSQL( sql );

			String[] vars = 
			{
				sql, 
				""
			};
			throw trataErro( "preparaSQL(String sql)", new GeneralException( e, vars ) );
		}

		return ps;
	}

	/**
	 * Inicializa a execução da classe.
	 */
	public boolean start( ) throws Exception
	{
		dsc = null;
		if( ( this.session == null ) || ( this.application == null ) )
			throw trataErro( "setSessao(HttpSession session)", new Exception( "Verifique se o contexto e a sessão foram definidos." ) );

		try
		{
			dsc = new DataSourceConnection( );
			log.setJDBC( "" );
			log.setURL( dsc.getJNDI_URL( ) );
		}
		catch( NamingException e )
		{
			String[] vars = 
			{
				adi.componentes.sql.DataSourceConnection.JNDI_URL )
			};
			throw trataErro( "setSessao(HttpSession session)", new GeneralException( e, vars ) );
		}
		catch( Exception e )
		{
			throw trataErro( "setSessao(HttpSession session)", new Exception( e ) );
		}
		return true;
	}
	/**
	 *
	 */
	public String getErrorPage( )
	{
		return application.getInitParameter( "excessoesPath" ) + "/erro.jsp";
	}
	/**
	 *
	 */
	public String getExceptionVar( )
	{
		int i = 0;
		while( session.getAttribute( "exception" + i ) != null )
			i++;

		return "exception"+i;
	}
	/**
	 * Gera log.
	 */
	protected Exception trataErro( String metodo, Exception exception )
	{
		fechaConexao( false );
		this.erro = String.valueOf( exception );

		log.setMetodo( "adi.componentes.sql.DBConnection." + metodo );
		log.setException( String.valueOf( exception ) );

		try
		{
			log.gerarLog( );
		}
		catch( LogException e )
		{
		}
		
		return exception;
		/*
			this.session.setAttribute( "exception", exception );

			if( response != null )
			{
				this.erro = null;
				try
				{
					//response.sendRedirect( application.getInitParameter( "excessoesPath" ) + "/erro.jsp" + "?redirect=1" );
					response.resetBuffer( );
					response.reset( );
					response.sendError( 500, exception.toString( ) );
				}
				catch( Exception e )
				{
					System.out.println( "Erro de redirect - " + e );
					/*
					try
					{
						response.reset( );
						response.setContentType( "text/html" );
						PrintWriter out = response.getWriter( );
						//out.flush( );
						out.write( "<html><head>" );
						out.write( "<script>top.location.href='" + application.getInitParameter( "excessoesPath" ) + "/erro.jsp" + "?redirect=2'</script>" );
						out.write( "</head></html>" );
						out.flush( );

						response.flushBuffer( );
						//força toda a liberação do buffer.
						while( response.isCommitted( ) );
					}
					catch( Exception e1 )
					{
						System.out.println( "Erro de redirecionamento do usuário > " + e1 );
					}
					
				}
			}
		}
		catch( LogException e )
		{
		}
		*/
		
	}
	
	/**
	 * Retorna objeto Connection utilizado pela classe.
	 */
	public Connection getConnection( )
	{
		return this.con;
	}

	/**
	 *
	 */
	public Object clone( ) throws CloneNotSupportedException
	{
		return new DBConnection( con, stmt, dsc, log, application, session, erro );
	}
}

Bom… são esses ai os arquivos… obrigado pela atenção… Flws!

3 Respostas

W

Cara poste o stack trace ai para a gente ver qual é o erro, tipo ele está se desconectando sozinho você tem que cuidar das conexões que foram abertas e ter certeza que elas foram fechadas ao termino da transação, e também se o usuario não está recebendo a mesma sessão. Também existe um comando no mysql que se auto reconecta ao banco quando desconectar, mas no Postgre não sei qual comando é.

D

WWatermann, estou utilizando o PostgreSQL 7.3… Na verdade não ocorre um erro específico que possa ser listado aki… Andei gerenciando o servidor para ver as conexões que estão executando, e reparei que mesmo após fechada o processo continua no servidor… Acredito que seja algo relacionado ao pool de conexões que o tomcat faz… Talvez seja alguma configuração… Ai a medida que outros usuários estão acessando o sistema parece que acabam as conexões e o sistema para de responder devido algumas validações que são feitas no banco ao carregar uma página…

D

aos moderadores

podem trancar este topico… por problemas de conexao, 2 topicos iguais foram adicionados… podem deixar somente o outro aberto…

Criado 20 de dezembro de 2004
Ultima resposta 21 de dez. de 2004
Respostas 3
Participantes 2