ERROR CONNECTING: TIMEOUT EXPIRED
Em um Módulo faço a conexão do banco, que é onde começou a dar o problema ao abrir a conexão
MySql.Data.MySqlClient.MySqlException: 'error connecting: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.'
public static MySqlConnection ConectaBanco()
{
Conexao = new MySqlConnection($"server =localhost;user id=root;database=meubanco;password=123456; Allow Zero Datetime = True");
Conexao.Open();
return Conexao;
}
E aqui em outro módulo onde acesso a conexão com o banco de dados, abro a conexão, consulto / incluo o que precisa e fecho a conexão
public static DataTable MostraDados(string Sql = "")
{
DataTable Dt = new DataTable();
var Cmd = ConectaBanco().CreateCommand();
Cmd.CommandText = Sql;
Da = new MySqlDataAdapter(Cmd.CommandText, ConectaBanco());
Da.Fill(Dt);
Conexao.Close();
return Dt;
}
public static int Gravar(string Sql = "", string NomeTabela = "")
{
int CodGerado = 0;
var Cmd = ConectaBanco().CreateCommand();
Cmd.CommandText = Sql;
Cmd.ExecuteNonQuery();
Conexao.Close();
}
Estava buscando algumas soluções e encontrei que colocando Pooling=false , na string de conexão poderia resolver o problema, más com esse comando me da o erro
MySql.Data.MySqlClient.MySqlException: 'Too many connections'
Não tem tratamento desse sistema na memória e não tem como eu recomeçar o tratamento, pois foram mais de 9 horas de tratamento , estou tentando resolver esse problema ainda com o projeto aberto
Eu poderia até recomeçar o tratamento, desde que não tivesse o risco de acontecer o mesmo problema
O que consegui foi colocar um Application.DoEvents(); em alguns pontos e a importação rodou bem por um tempo
Más lembrando que todo o problema começou após ter mais de 7 milhões de registros tratados
Agradeço a todos pela ajuda
using(MySqlConnection Conexao = new MySqlConnection($"server =localhost;user id=root;database=meubanco;password=123456; Allow Zero Datetime = True"))
Deu a mesma mensagem de erro
Que tal fazer isso (conecta/desconecta) a cada X linhas ?
Eu tive esse tipo de situação uns bons anos atrás, a solução foi meio que criar um valor de alterações que faria e depois submeter todas.
Assim, pode ser chover no molhado, e sei que dá mais trabalho...mas sinceramente tenta fazer DIRETO no banco via stored procedure lendo o arquivo para uma tabela temporária, fatiando e lendo, pois assim é ele com ele mesmo.
Sempre que precisei (depois que aprendi isso) nunca mais usei intermediários, leio e gravo o que preciso diretamente via banco (mais saudável, garantido e performático).
public static DataTable MostraDados(string Sql = "")
{
DataTable Dt = new DataTable();
var Cmd = ConectaBanco().CreateCommand();
Cmd.CommandText = Sql;
Da = new MySqlDataAdapter(Cmd.CommandText, ConectaBanco());
Da.Fill(Dt);
Conexao.Close();
return Dt;
}
Nesse código seu você abre duas conexões e só fecha uma delas
A primeira você abre na linha "var Cmd = ConectaBanco().CreateCommand()"
A segunda na linha Da = new MySqlDataAdapter(Cmd.CommandText, ConectaBanco());
Cada vez que você chama o ConectaBanco() ele abre uma nova conexão e aparentemente guarda ela na variável Conexao que parece ser uma variável global, eu diria pra você se livrar dessa variável, ela facilita muito de ter problemas, eu diria pra você simplesmente retornar a nova conexão no seu método ConectaBanco(), algo do tipo
public static MySqlConnection ConectaBanco()
{
var cnn = new MySqlConnection($"server =localhost;user id=root;database=meubanco;password=123456; Allow Zero Datetime = True");
cnn.Open();
return cnn;
}
E você precisa garantir que qualquer lugar que use ele feche todas as conexões que abrir, idealmente abra apenas uma conexão de cada vez se for possível
Então mudaria o código do MostraDados para usar a conexão assim:
public static DataTable MostraDados(string Sql = "")
{
using (var cnn = ConectaBanco())
{
DataTable Dt = new DataTable();
Da = new MySqlDataAdapter(sql, cnn);
Da.Fill(Dt);
cnn.Close();
}
return Dt;
}
Outro erro
var Cmd = ConectaBanco().CreateCommand();
Cmd.CommandText = Sql;
Da = new MySqlDataAdapter(Cmd.CommandText, ConectaBanco());
Aqui você cria um Command mas não usa ele, você simplesmente coloca a SQL no CommandText dele e depois pega de volta esse valor pra passar pro DataAdapter, é o mesmo que passar direto o valor da variável Sql
Objetos de banco, MySqlConnection, DataTable, MySqlDataAdapter, comando... todos eles são "disposable". Portanto além de fechar a conexão, o objeto dela precisa ser destruído para ser coletado pelo GAC(Garbage collector). Caso isso não seja feito, consiste em um memory leak e vai "comendo" a memória RAM da máquina.
Mais uma razão para usar blocos using e mais uma razão para usar OOP.
ALVARO2009, não fique bravo com minha crítica, mas um código assim, não passaria por review nem mesmo para um dev junior. Recomendo fortemente que reveja seus conhecimentos de desenvolvimento e implemente boas práticas. Isso vai te evitar MUITAS dores de cabeça no futuro. Se quiser, podemos ajudar nessa jornada de aprimoramento. Você vai gastar um tempo aprendendo essas coisas, mas com certeza vai ganhar muito tempo no futuro. Na prática, gasta umas horas agora, para ganhar várias semanas e até meses em tempo no futuro. Fora que vai abrir MUITO os horizontes pra você.
SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
Uma coisa que eu não faço, é colocar uma questão aqui e ficar esperando a ajuda, eu procuro ir atrás das soluções e tentar resolver(mesmo porque como ainda tenho pouca experiência com a linguagem, preciso aprender muita coisa) então as vezes acontece de eu conseguir resolver, antes de ter a resposta de vcs ou mesmo ver o retorno, que foi esse o caso que acabou acontecendo.
Eu vim aqui para encerrar o tópico e colocar o erro que acabei achando, para que futuramente caso alguém tenha o mesmo problema, possa achar uma possível solução
Más fiquei feliz por ter encontrado o problema e a solução que achei foi proposta por vcs ( e bem melhorada diga-se de passagem ) e tem uma coisa que não tinha pensado, que foi a solução do Webmaster
Webmaster - vou procurar ver como que faz essa leitura e jogar diretamente no banco de dados o arquivo, acredito que possa ficar mais rápido, porque o que estou fazendo é abrindo ele com o StreamReader e lendo linha a linha, e importando apenas o que me interessa
Será que vc poderia me passar o esquema de como fazer esse tratamento diretamente no banco de dados ?
Se vc puder me mandar no meu email ( alvaro.bernardi@bol.com.br) , fico muito agradecido, más de qqer forma irei atrás dessa solução
Kerplunk - Estive mesmo olhando o código e vendo se tinha alguma coisa que deixei passar, e acabei vendo que tinha sim, a conexão estava sendo aberta 2x, foi o problema que o Ocelot passou
Ocelot - Analisando linha a linha com o F11 , achei exatamente o problema que vc colocou, abri 2x o banco no meu mostradados, deixando ele assim
DataTable Dt = new DataTable();
Da = new MySqlDataAdapter( Sql, ConectaBanco());
Da.Fill(Dt);
Conexao.Close();
return Dt;
Porém não tinha me atendado para o tratamento para a variável Global que eu tinha feito, e estou usando a sua solução que vc passou, más primeiramente entendi perfeitamente o tratamento que vc deu, e tirei até mesmo os Application.DoEvents() , deixando a importação mais rápida, mesmo que trave de momento a aplicação, como ela é feita nesse momento só para a importação não tem problema
Mais uma vez agradeço a todos, por enqto deixarei aberto para poder receber qqer comentário
Um dos problemas que vejo, é a falta de entendimento da herança. Por exemplo, se você observa a documentação da classe MySqlDataAdapter que você usa. Na sessão "implements", você vai observar que tem a interface IDisposable. Isso significa que instâncias dessa classe(sempre que você usar ela em código), você precisa ou chamar o método Dispose() assim que terminar de usar a instância do objeto ou colocar o código em que você usa essa instância dentro de um bloco using, mais ou menos assim:
Esse código, poderia ser um método:
Da = new MySqlDataAdapter( Sql, ConectaBanco());
Da.Fill(Dt);
Conexao.Close();
return Dt;
O método ficaria mais ou menos assim:
public DataTable GetDataTableFromQuery(string connectionString, string query)
{
DataTable dataTable = new DataTable();
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
using (MySqlDataAdapter adapter = new MySqlDataAdapter(query, connection))
{
connection.Open();
adapter.Fill(dataTable);
}
}
return dataTable;
}
Isso garantiria que tanto a conexão quando o DataAdapter seriam abertos, fechados e dispostos corretamente.
Citação:Concordo com o OCELOT e digo mais:Objetos de banco, MySqlConnection, DataTable, MySqlDataAdapter, comando... todos eles são "disposable". Portanto além de fechar a conexão, o objeto dela precisa ser destruído para ser coletado pelo GAC(Garbage collector). Caso isso não seja feito, consiste em um memory leak e vai "comendo" a memória RAM da máquina.Mais uma razão para usar blocos using e mais uma razão para usar OOP.ALVARO2009, não fique bravo com minha crítica, mas um código assim, não passaria por review nem mesmo para um dev junior. Recomendo fortemente que reveja seus conhecimentos de desenvolvimento e implemente boas práticas. Isso vai te evitar MUITAS dores de cabeça no futuro. Se quiser, podemos ajudar nessa jornada de aprimoramento. Você vai gastar um tempo aprendendo essas coisas, mas com certeza vai ganhar muito tempo no futuro. Na prática, gasta umas horas agora, para ganhar várias semanas e até meses em tempo no futuro. Fora que vai abrir MUITO os horizontes pra você.
Quando respondi a primeira vez, não vi que tinha um comentário seu, acho que eu estava com a questão aberta e vi somente agora
Quanto a eu ficar bravo, NUNCA, sei que é uma critica construtiva, e isso para mim é importante. Realmente no C# estou engatinhando e esse erro que postei aqui, é uma das dores de cabeça que poderiam ter sido evitadas.
Os cursos que andei fazendo para conhecer a ferramenta, me deram uma base e é nessa base que estou desenvolvendo, ainda não 100%, pois tenho muitos projetos no vb6, más novos projetos estou procurando já iniciar no C#, e com isso quero aprender boas práticas para poder melhorar o meu desenvolvimento
Quanto a sua pergunta
Citação:Quantas tabelas tem no seu banco? Pode colocar a estrutura dele aqui? Você pode rodar essa query para mostrar isso:SELECT *FROM INFORMATION_SCHEMA.COLUMNS
Nesse projeto tem apenas 10 tabelas, más o script que vc pediu para rodar, pegou todas as bases que tenho, e deu
/* Affected rows: 0 Registros encontrados: 16.105 Avisos: 0 Duração de 1 query: 1,641 sec. (+ 0,062 sec. network) */
Crie classes que sejam "correspondentes" à cada tabela. Tipo, a tabela Cliente tem campos "Id integer" e "Nome Varchar", crie uma classe assim:
public class Cliente{
public int Id { get; set; }
public Nome { get; set; }
}
Coloque sempre os tipos de dados correspondentes em cada propriedade. DateTime para Date, string para varchar, int para integer e por aí vai.
Pode criar todas essas classes num arquivo só e de preferência dentro de um mesmo namespace.
Quando tiver isso pronto, me chama que podemos implementar o mini ORM que subi aqui no VBMANIA, a gente faz uma sessão "fora de hora" e te ajudo nisso. Vamos fazer teu código ficar muito bom. :)