Pergunta

Eu tenho um webapp que usa JNDI pesquisas para obter uma conexão com o banco de dados.

A conexão funciona bem e retorna a consulta sem problemas.O problema-nos que a ligação não fechar corretamente e está preso no modo "sono" (de acordo com o mysql administrator).Isso significa que eles tornam-se inutilizáveis nad depois que eu acabar de conexões.

Alguém pode me dar algumas dicas do que eu posso fazer para fazer a conexão de retorno para a piscina com êxito.

public class DatabaseBean {

private static final Logger logger = Logger.getLogger(DatabaseBean.class);

private Connection conn;
private PreparedStatement prepStmt;

/**
 * Zero argument constructor
 * Setup generic databse connection in here to avoid redundancy
 * The connection details are in /META-INF/context.xml
 */
public DatabaseBean() {
    try {
        InitialContext initContext = new InitialContext();
        DataSource ds = (DataSource) initContext.lookup("java:/comp/env/jdbc/mysite");
        conn = ds.getConnection();
    }
    catch (SQLException SQLEx) {
        logger.fatal("There was a problem with the database connection.");
        logger.fatal(SQLEx);
        logger.fatal(SQLEx.getCause());
    }
    catch (NamingException nameEx) {
        logger.fatal("There was a naming exception");
        logger.fatal(nameEx);
        logger.fatal(nameEx.getCause());
    }
}

/**
 * Execute a query. Do not use for statements (update delete insert etc).
 *
 * @return A ResultSet of the execute query. A set of size zero if no results were returned. It is never null.
 * @see #executeUpdate() for running update, insert delete etc.
 */

public ResultSet executeQuery() {
    ResultSet result = null;
    try {
        result = prepStmt.executeQuery();
        logger.debug(prepStmt.toString());
    }
    catch (SQLException SQLEx) {
        logger.fatal("There was an error running a query");
        logger.fatal(SQLEx);
    }
    return result;
}

RECORTE

public void close() {
    try {
        prepStmt.close();
        prepStmt = null;

        conn.close();
        conn = null;
    } catch (SQLException SQLEx) {
        logger.warn("There was an error closing the database connection.");
    }
}
}

Isso está dentro de um javabean que usa a conexão de banco de dados.

public LinkedList<ImportantNoticeBean> getImportantNotices() {

    DatabaseBean noticesDBBean = new DatabaseBean();
    LinkedList<ImportantNoticeBean> listOfNotices = new LinkedList<ImportantNoticeBean>();

    try {
        PreparedStatement preStmt = noticesDBBean.getConn().prepareStatement("SELECT pseudonym, message, date_to, date_from " +
                "FROM importantnotices, users " +
                "WHERE importantnotices.username = users.username " +
                "AND NOW() >= date_from AND NOW() <= date_to;");

        noticesDBBean.setPrepStmt(preStmt);
        ResultSet result = noticesDBBean.executeQuery();

        while (result.next()) {
            ImportantNoticeBean noticeBean = new ImportantNoticeBean();

            noticeBean.setAuthor(result.getString("pseudonym"));
            noticeBean.setMessage(result.getString("message"));
            noticeBean.setDateTo(result.getDate("date_to"));
            noticeBean.setDateFrom(result.getDate("date_from"));

            listOfNotices.add(noticeBean);
        }

        result.close();

    } catch (SQLException SQLEx) {
        logger.error("There was an error in ImportantNoticesBean.getImportantNotices()");
        logger.error(SQLEx);
    } finally {
        noticesDBBean.close();
    }
    return listOfNotices;
}

<Context reloadable="true">

    <Resource name="jdbc/mysite"
              auth="Container"
              type="javax.sql.DataSource"
              username="user"
              password="password"
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/mysite"
              maxActive="10"
              maxIdle="5"
              maxWait="6000"
              removeAbandoned="true"
              logAbandoned="false"
              removeAbandonedTimeout="20"
            />
</Context>
Foi útil?

Solução 4

O problema-nos que a ligação não fechar corretamente e está preso no modo "sono"

Este foi, na verdade, apenas a metade direita.

O problema que eu tive foi, na verdade, que cada aplicativo foi a definição de uma nova conexão para o banco de dados de servidor.Assim, cada vez que eu fechei todas as conexões de Aplicativo de Um gostaria de fazer um monte de novas ligações, conforme é WEB.xml arquivo de configuração e executar feliz.Aplicativo B faria o mesmo.O problema é que eles são independente de piscinas que tenta agarrar ao servidor o limite definido.É uma espécie de condição de corrida, eu acho.Assim, quando Um Aplicativo tem acabado com as conexões que se senta esperando para usá-los novamente até que esgotado o tempo limite enquanto App B que tem a conexão agora é negada a recursos, mesmo que A App tem acabado com o e deve estar de volta na piscina.Uma vez esgotado o tempo limite, a conexão é liberada e B (ou C, etc) pode chegar a ele novamente.

exemplo:se o limite é de 10 (mySQL limite de perfil) e que cada aplicativo tenha sido configurado para usar um máximo de 10, haverá 20 tentativas de conexões.Obviamente esta é uma situação ruim.

A solução é RTFM e colocar o detalhes de conexão no lugar certo.Isto faz compartilhado a postagem de uma dor, mas existem maneiras de contornar isso, (tais como links para outros arquivos xml a partir do contexto).

Apenas para ser explícita:Eu coloquei os detalhes de conexão do WEB.xml para cada aplicativo e teve uma briga sobre isso.

Outras dicas

Você parece estar fechando a conexão corretamente, exceto para o caso de prepStmt.fechar() lança uma SQLException, eu não consigo encontrar uma conexão vazamento.

O que o pool de implementação que você está usando?Quando você fechar uma conexão, a piscina não precisa fechar o subjacente conexão com o MySQL imediatamente - depois de tudo o que está a ponto de um pool de conexão!Assim, a partir do MySQL lado, as conexões ficaria vivo, embora sua aplicação não está a utilizar qualquer;eles podem simplesmente ser realizada pelo TC pool de conexão.

Você pode querer experimentar com as configurações do pool de conexões.Peça para diminuir o pool quando o sistema está ocioso.Ou, se pedir para atualizar todas as conexões periodicamente.Ou, ter um rigoroso limite superior do número de conexões simultâneas que já fica do MySQL etc.

Uma forma de verificar se seu código tenha uma conexão de fuga é para forçar o ds.getConnection() para abrir uma nova conexão física e conn.close() para liberar a conexão (se o pool de conexão tem configurações para essas).Então, se você assistir as conexões no MySQL lado, você pode ser capaz de descobrir se o código realmente tem uma ligação fuga ou não.

Esta é uma pergunta semelhante - Pool de conexão Configurações do Tomcat

Esta é a minha resposta para essa pergunta, e ele resolveu o problema para o outro cara.Ele pode ajudar você também.

Tomcat Documentação

DBCP usa o Jakarta-Commons Conexão de Banco de dados para a Piscina.Ele se baseia no número de Jakarta-Commons componentes:

* Jakarta-Commons DBCP
* Jakarta-Commons Collections
* Jakarta-Commons Pool

Eu estou usando o mesmo pool de conexão coisas, e eu estou de definir estas propriedades, para evitar que a mesma coisa é só não configurado através do tomcat.Mas se a primeira coisa que não funciona tente estas.

testWhileIdle=true
timeBetweenEvictionRunsMillis=300000

Ok, eu poderia ter esse classificados.Eu mudei o banco de dados de configuração de recursos para o seguinte:

*SNIP*
maxActive="10"
maxIdle="5"
maxWait="7000"
removeAbandoned="true"
logAbandoned="false"
removeAbandonedTimeout="3"
*SNIP*

Isso funciona bem o suficiente para agora.O que está acontecendo, afaik, é que quando eu chegar a dez ligações, em seguida, o Tomcat é a verificação de ligações abandonadas (tempo ocioso > 3).Ele faz isso em um trabalho em lotes a cada vez que o número máximo de ligações é atingido.O potencial problema com isto é que se eu precisar de mais de 10 consultas executadas ao mesmo tempo (não é a única para mim).O importante é que removeAbandonedTimeout é menor do que maxWait.

Isso é o que deve estar acontecendo?ou seja, É este o caminho que a piscina deve operar?Se for, parece, pelo menos para mim, que você deve esperar até que algo (a ligação) é interrompida antes da fixação, em vez de não deixá-lo 'quebrar' em primeiro lugar.Talvez eu ainda não estou entendendo.

Uma coisa que @binil perdeu, você não fechar o conjunto de resultados no caso de uma exceção.Dependendo da implementação do controlador isso pode causar a ligação para ficar aberta.Mova o resultado.fechar() chamada para o bloco finally.

Eu estou usando a mesma configuração como você está.Se a conexão no mysql administrator(windows) mostra que ele está no modo de suspensão significa apenas que é pool, mas não em uso.Eu verifiquei esta executando um programa de teste do programa com vários threads, tornando aleatório consultas para Mysql.se isso ajuda, aqui está a minha configuração:

        defaultAutoCommit="false"
        defaultTransactionIsolation="REPEATABLE_READ"
        auth="Container"
        type="javax.sql.DataSource"
        logAbandoned="true" 
          removeAbandoned="true"
        removeAbandonedTimeout="300" 
        maxActive="-1"
        initialSize="15"
        maxIdle="10"
        maxWait="10000" 
        username="youruser"
        password="youruserpassword"
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://yourhost/yourdatabase"/>
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top