[RESOLVIDO] Dúvida sobre funcionamento de conexão com banco de dados utilizando métodos static

Bom dia eu tenho o seguinte método que efetua conexões pra mim e todos os meus sistemas:

[code]public class ConexaoSQL implements ConexaoDao {

@Override
public  Connection getConexao() {

	Connection conn = null;
	try {
		// Carrega o driver JDBC especfico para o banco de dados MySQL
		String driver = "com.mysql.jdbc.Driver";
		Class.forName(driver);

		// Estabelece a conexao com o banco de dados
		String url = "jdbc:mysql://192.168.0.2?zeroDateTimeBehavior=convertToNull&user=root&password=powerful";
		conn = DriverManager.getConnection(url);
		// Se chegou porque a conexo foi feita com successo
		System.out.println("Conexao estabelecida com sucesso");

	} catch (ClassNotFoundException e) {
		e.printStackTrace();

	} catch (SQLException e) {
		e.printStackTrace();
	}
	return conn;

}[/code]

E outra classe onde eu tenho métodos prontos que efetuam Querys para mim: ( onde neste método eu crio e fecho a conexão (teóricamente));

[code]public class CommandSQL {

static ConexaoDao conector = new ConexaoSQL();

private static Connection conn;

public static int executeSqlLine(String sql) throws SQLException {

    conn = conector.getConexao();
    PreparedStatement ps = conn.prepareStatement(sql);

    Arquivo.gravaLog("Executando linha " + sql);
    ps.execute();
}

public static ResultSet executeSqlQuery(String sql) throws SQLException {

    conn = conector.getConexao();
    PreparedStatement ps = conn.prepareStatement(sql);
    System.out.println(sql);
    Arquivo.gravaLog("Executando linha " + sql);
    return ps.executeQuery();

}

public static void closeSqlConnection() {
    try {
        conn.close();
    } catch (SQLException e) {
        Arquivo.gravaLog(e.getMessage() + " Close SQL Connection - CommandSQL");
    }
}

[/code]

Eu utilizo estes métodos assim:

public void selectColaboradores(){
      try{
             ResultSet rs = CommandSQL.executeSqlQuery("SELECT * FROM colaboradores");
      } catch (SQLException sql){
              System.out.println(sql.getMessage());
      } finally {
              CommandSQL.closeSqlConnection();
      }

Gostaria de saber se esta forma como estou programando está abrindo e fechando a conexão com o banco de dados corretamente e que tipo de problemas este tipo de conexão pode
me causar e porquê.

Tenho diversos projetos e todos eles utilizam esta classe pra efetuar consultas sql.

Estava analisando as conexões com o banco de dados pela ferramenta MySQL Administrator

E percebi na aba User Connections que raramente o número de conexões é menor que 30 (média de 40 a 70), sendo que na minha empresa temos apenas 27 usuários

O problema é que os usuários não utilizam o sistema com frequência, e a unica coisa que fica rodando Querys é o Chat interno que atualiza o status de cada usuário a cada 30 segundos, cada usuário envia uma resposta de status (Online, Ausente, Ocupado) pra um servidor e o mesmo atualiza o status deste usuário no banco de dados. Quando um usuário
deixa de estar conectado por mais de 1 minuto e meio o status deste usuário é setado no banco de dados como Offline. Esta é a unica Thread envolvendo banco de dados que fica rodando em background em todas as máquinas.

Este volume de conexões que eu vi no MySQL Administrator está correto? Percebi que na coluna “Command” o tipo da maioria das conexões é Sleep, isso significa que a conexão esta ativa ou não? meu método está fechando as conexões corretamente?

Uma coisa que também tem me incomodado um pouco é que alguns sistemas que estou desenvolvendo está sendo necessário à utilização de consultas sql em Threads simultaneas utilizando a mesma classe estática CommandSQL, em alguns momentos (raros) acontece o erro de Comunications Link Failure the last packet send a 2 miliseconds ago, acredito que isso aconteça porque a Thread esta tentando acessar a conexão estática da classe CommandSQL ao mesmo tempo que outra Thread, pensando nisso fiz com que estas Threads utilizassem o synchronized

  @Override
    public synchronized void run() {}

Mesmo utilizando o synchronized isso acontece, porquê?

Lembrando que todas essas perguntas vão servir para aprimorar meu conhecimento, não estou criando este tópico para resolver problemas na empresa e sim para compreender melhor algumas coisas.

Agradeço toda a ajuda.

Olá amigo, vou tentar ajudar ok?
Seguinte, o problema está no método getConexao. Acontece o seguinte, mesmo a ConexaoDao sendo estático, toda vez que ela chama o método getConexao, ele cria uma nova conexao com o banco (imagina um cenario onde multiplas threads chamam metodos do CommandSQL, neste caso ele criara varias conexoes com o banco e deixando as anteriores aberta, e no final ele só fechará uma). A melhor maneira no seu caso que é que a variavel conn seja static fora do metodo getConexao() e toda vez que for chamar o metodo getConexao() verificar antes se já não existe uma conexão aberta (para que todas as Threads utilizem a mesma conexao) ou seja dai voce faz um if(conn != null) return conn;
Neste caso digo do conn de dentro do ConexaoSQL. Apesar do conn que voce criou na classe CommandSQL seja static, ele ainda ira abrir varias conexoes com o banco para o método getConexao quando executado.

Não sei se consegui te explicar, mas seria esse o problema. Tente realizar esse teste... ai nenhuma variavel mais precisará ser estática, o importante neste caso é que a conexão seja e que a mesma conexão seja usada por todas as threads (claro, caso a conexão esteja fechada, voce pede para ele abrir novamente).

Como por exemplo ficaria assim?:

[code] public class CommandSQL {

    static ConexaoDao conector = new ConexaoSQL();  
  
    private static Connection conn;  
  
    public static int executeSqlLine(String sql) throws SQLException {  
  
        if(conn == null || conn.isClosed()){
                     conn = conector.getConexao();
        }
        PreparedStatement ps = conn.prepareStatement(sql);  
  
        Arquivo.gravaLog("Executando linha " + sql);  
        ps.execute();  
    }  
  
    public static void closeSqlConnection() {  
        try {  
            conn.close();  
        } catch (SQLException e) {  
            Arquivo.gravaLog(e.getMessage() + " Close SQL Connection - CommandSQL");  
        }  
    }  [/code]

A proposito ajudou muito sim

Então, acho que isso funciona assim, porque cada Thread de CommandSQL compartilharam a variavel Connection. Recomendo você fazer vários testes e acompanhar as conexoes criadas. Caso de algum problema, posta ai porque ja imaginei alguns problemas que isso pode causar.

Ah, estou tentando melhorar sua arquitetura ai e não estou propondo outra ( que neste caso poderia indicar frameworks que fazem isso e muito bem por sinal).

[quote=jonathan.c.rodrigues]Então, acho que isso funciona assim, porque cada Thread de CommandSQL compartilharam a variavel Connection. Recomendo você fazer vários testes e acompanhar as conexoes criadas. Caso de algum problema, posta ai porque ja imaginei alguns problemas que isso pode causar.

Ah, estou tentando melhorar sua arquitetura ai e não estou propondo outra ( que neste caso poderia indicar frameworks que fazem isso e muito bem por sinal). [/quote]

Quais problemas isso pode causar? na questão da Threads foi mais uma questão de dúvida mesmo, quando acontece um erro relacionado a conexão em uma dessas Threads a mesma é reiniciada então isso não afeta o processamento de forma significativa. O que mais me chamou atenção mesmo foi o volume de trafego no MySQL com um sistema tão pequeno, então, sabia que havia algo errado. Por esse motivo acredito que havia muitas conexões como SLEEP, estou nesse momento recompilando todos os sistemas e ja vou reinicia-los para fazer o teste.

No caso de Frameworks que você me indicaria, seria por exemplo Hibernate?

Gostaria de saber também se este é um “bom” modelo de arquitetura levando em consideração as modificações feitas.

Na verdade para gerenciar conexões seria o Spring. Um dos problemas que vi seria quando varias threads ja tenha pegado aquela conexao e uma dessa threads a fecha. As outras daram erro (porque o objeto conn já não existe mais)dependendo do ponto aonde essas threads estão do codigo.

Mas faça o teste em um ambiente local ou de testes certo ? Nunca suba isso em produção sem testar muito bem. (Na verdade, teste muito bem qualquer coisa que você fizer hehehe)

[quote=jonathan.c.rodrigues]Na verdade para gerenciar conexões seria o Spring. Um dos problemas que vi seria quando varias threads ja tenha pegado aquela conexao e uma dessa threads a fecha. As outras daram erro (porque o objeto conn já não existe mais)dependendo do ponto aonde essas threads estão do codigo.

Mas faça o teste em um ambiente local ou de testes certo ? Nunca suba isso em produção sem testar muito bem. (Na verdade, teste muito bem qualquer coisa que você fizer hehehe)[/quote]

Eu pensei nisso que você disse portanto fiz a mesma verificação no fim da conexão:

        public static void closeSqlConnection() {    
            try {     
               if(conn != null){
                 if(!conn.isClosed()){
                      conn.close();    
                 }
              }
            } catch (SQLException e) {    
                Arquivo.gravaLog(e.getMessage() + " Close SQL Connection - CommandSQL");    
            }    
        }    

Opa tinha esquecido… é isso mesmo! Tinha que fazer no close também essa verificação. Depois de uma olhada em Design Patterns e olha o Singleton… Ai já da para você entender bem o porque disso.

Vou olhar com certeza, muito obrigado mesmo eslareceu muitas de minhas dúvidas