Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Juliano amadeu

[Resolvido] Erro too many connections

Recommended Posts

Tenho um script relativamente simples que está retornando o erro Too Many Connections do MySql e não sei mais o que posso fazer.

 

Tentei reproduzir o erro juntando as rotinas que apresentam o erro. O código é esse:

foreach($res as $key=>$value){
$resposta->setIdPesquisa($res[$key]['id']);
$pergunta->setIdPesquisa($res[$key]['id']);
$questionario->setIdPesquisa($res[$key]['id']);
$crud = new Crud();
$arrQuestionariosIniciados = $crud->selectWithCriteria('qresposta_basico',array(new TFilter('id_pesquisa', '=', $pergunta->getIdPesquisa())), null);
$arrPerguntas = $pergunta->retrieveAll('cad_questionario_pergunta');

$total = 0;

foreach($arrQuestionariosIniciados as $Qkey=>$Qvalue){
	foreach($arrPerguntas as $key=>$value){
		AQUI ESTÁ O ERRO ===>$arrRespostas = $resposta->retrieveWithCriteria(array('id_pergunta'=>$arrPerguntas[$key]['id'], 'id_basico'=>$arrQuestionariosIniciados[$Qkey]['id']));
		$total = (int)count($arrRespostas);
	}
}	
//$ret = $questionario->numQuestionariosRespondidos($pergunta, $resposta);
$research->getAmostraTotal($res[$key]['id']);
echo "teste";
}

 

Se eu comento a linha do erro, os loops acontecem normalmente.

Este script está rodando em um servidor com 1Gb de RAM.

 

O mysql está com 150 conexões máximas. Já tentei aumentar para 1000, mas o erro continua. Alguém tem alguma pista do que posso fazer?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Posta a classe cuja instância está armazenada em $resposta e, adicionalmente a classe Crud.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Oi Bruno, o método da classe resposta que está sendo utilizado é este:

 

public function retrieveWithCriteria($arrCriteria){
	$sql = new TSqlSelect();
	$sql->setEntity('qresposta');
	$sql->addColumn('*');
	$criteria = new TCriteria();
	foreach($arrCriteria as $key=>$value){
	$criteria->add(new TFilter($key, '=', $value));
	}
	$sql->setCriteria($criteria);
	$this->query = $sql->getInstruction();

	$this->res = TSql::selectAll($this->query);

	if (PEAR::isError($this->res))
	{
		print_r($this->res);
		return false;
	}

	return $this->res;		
}

 

e o método da classe CRUD que está sendo utilizado é basicamente o mesmo.

 

public function selectWithCriteria($entity, array $tFilter, $arrProp, $debug=false){
	$sql = new TSqlSelect();
	$sql->setEntity($entity);
	$sql->addColumn('*');

	$criteria = new TCriteria();

	if(isset($arrProp)){
		foreach($arrProp as $key=>$value)
		$criteria->setProperty($key, $value);
	}

	if(isset($tFilter)){
		foreach($tFilter as $key=>$value)
		$criteria->add($value);
	}

	$sql->setCriteria($criteria);

	$this->query = $sql->getInstruction();

	if($debug)
	echo "<pre>".$this->query ."<BR></pre>";

	$this->res = TSql::selectAll($this->query);

	return $this->res;
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

Oi Igor,

 

como vai?

 

Desculpe, mas não entendi suua colocação.

Uso o pacote MDB2 do PEAR para abstração do banco de dados. É amplamente utilizado (inclusive em meus outros projetos) e nunca tive problemas com ele. Não acredito que o erro esteja no PEAR, mas sim em como o estou utilizando, apenas não consigo encontrar esta falha que está sobrecarregando o mysql.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Poste o construtor da classe Crud, por favor.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ok, é que olha o seguinte:

 

foreach($res as $key=>$value){

       foreach($arrQuestionariosIniciados as $Qkey=>$Qvalue){
               foreach($arrPerguntas as $key=>$value){

 

caracaa!!!! 3 loops encaixados!!

de onde eu venho e qndo aprendi a programar, me diziam algo como: se você precisa de mais que 2 loops encaixados, então provavelmente o teu algoritmo está errado(existem ressalvas).

 

 

O meu chute, é que dentro de algum desses loops você esteja se conectando ao banco, assim a cada iteração criando uma nova conexão. Entendeu ?

Somente conhecendo todo o projeto, e todos os códigos atrelados é que eu poderia te dizer algo com mais precisão. Mas este é o meu feeling com os dados que você forneceu.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Oi William,

 

realmente está confuso, mas esse script foi feito apenas para reproduzir o erro do projeto, por isso os loops.

Classe de conexão:

 

class Conn{

private function __construct() {}

public static function open()
{
	/*Local*/
	$db_tipo="mysqli";
	$user="root";
	$senha="";
	$host="xxxx";
	$dbName="xxxx";

	$dsn = "$db_tipo://$user:$senha@$host/$dbName?charset=utf8";
	$db = MDB2::factory($dsn);

	//$db->setOption('debug', 1);
	if (MDB2::isError($db)) {
		die($db->getMessage().' - '.$db->getUserinfo());
	}

	$db->setFetchMode(MDB2_FETCHMODE_ASSOC);
	if(MDB2::isError($db)) die($db->getMessage());

	return $db;
}

}

 

 

Classe que lida com o SQL.

 

class TSql{

private static $conn;

private function __construct() 
{
	if(empty(self::$conn))
	{
		self::$conn = Conn::open();
	}
	return self::$conn;
}


public function select($sth){
	$conn = Conn::open();
	$res = $conn->query($sth);

	$ret = $res->fetchRow();
	if(PEAR::isError($ret))
		return false;
	else
		return $ret;
}
public function selectAll($sth){
	$conn = Conn::open();
	$res = $conn->query($sth);
	if(PEAR::isError($res))
		return false;

	$ret = array(); // Variável de retorno

	while ($result = $res->fetchRow()){
		$ret[] = $result;
	}
	return $ret;
}
public function insert($sth, $retLastId=false){
	$conn = Conn::open();
	$ret = $conn->exec($sth);
	if(PEAR::isError($ret)){
		return $ret;
	}else{
		if($retLastId){
			$id = (int)$conn->lastInsertID($tabela, $campo);
			return $id;
		}else{
			return $ret;
		}
	}
}
public function update($sth){
	$conn = Conn::open();
	$ret = $conn->exec($sth);
	if(PEAR::isError($ret))
		return false;
	else
		return $ret;
}
public function delete($sth){
	$conn = Conn::open();
	$ret = $conn->exec($sth);
	if(PEAR::isError($ret))
		return false;
	else
		return $ret;
}

}	

Compartilhar este post


Link para o post
Compartilhar em outros sites

Oi @Juliano,

 

Agora o erro está evidente, e se encaixa com oque eu achei que fosse:

 

        public function select($sth){
               $conn = Conn::open();
//
       }
       public function selectAll($sth){
               $conn = Conn::open();
// 
       }
       public function insert($sth, $retLastId=false){
               $conn = Conn::open();
 //
       }
       public function update($sth){
               $conn = Conn::open();
//
       }
       public function delete($sth){
               $conn = Conn::open();
//
       }

ou seja, todos os métodos dessa Class, chamam diretamente o método Conn::open()

 

Ok, mas ai vemos que:

        public static function open()
       {
//
               $dsn = "$db_tipo://$user:$senha@$host/$dbName?charset=utf8";
               $db = MDB2::factory($dsn);

ou seja, o método open, abre uma nova conexão cada vez que é chamado!!!!

 

 

Logo, se você precisar fazer isso aqui na aplicação:

 

$TSql->select();
$TSql->select();
$TSql->select();

 

 

o seu conjunto de classes vai abrir 3 conexões com o banco. Desnecessariamente. Com uma única conexão tudo seria resolvido.

Assim fica fácil conseguir um "too many connections", concorda ?

 

 

:lol:

Compartilhar este post


Link para o post
Compartilhar em outros sites

como eu disse, tinha a haver com o pacote do pear...

 

checkmate

 

como eu disse, tinha a haver com o pacote do pear...

 

checkmate

? não tem absolutamente nada a ver com o pacote do PEAR.

 

E sim com um uso indiscriminado e incoerente de objetos e métodos. Você realmente entendeu a minha resposta ?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Mas o construtor checa se já existe conexão aberta, não é?

private function __construct() 
       {
               if(empty(self::$conn))
               {
                       self::$conn = Conn::open();
               }
               return self::$conn;
       }

 

Se existir conexão ele retorna a conexão que está aberta, ou estou errado?

Fiz dessa forma justamente para aproveitar a conexão já aberta pelo script.

Você vê algum erro nessa lógica.

 

Obrigado e um abraço.

Compartilhar este post


Link para o post
Compartilhar em outros sites

? não tem absolutamente nada a ver com o pacote do PEAR.

 

E sim com um uso indiscriminado e incoerente de objetos e métodos. Você realmente entendeu a minha resposta ?

sim, entendi, ele abre toda hora a conexao com o banco, mas você eh q nao entendeu a minha, como nao tem nada a ver com o pacote do pear?

 

kem faz as conexoes ao banco de dados? nao eh o mysqli...eh o mdb2, do pear, q ele usa se o erro diz q sao muitas conexoes ao banco, e eh o mdb2 q faz a conexao, o erro vai estar onde?

 

Mas o construtor checa se já existe conexão aberta, não é?

sim, ele checa, mas você não usa ele!

 

você usa o open direto!!

 

kem faz as conexoes ao banco de dados?

no caso dele é o mdb2

 

eh o mdb2 q faz a conexao, o erro vai estar onde?

o erro está na forma que ele está usando. E não no mdb2.

Se ele usar dessa forma, então não importa se é mysqli, mysql_, pdo.. whatever, vai acontecer o mesmo problema.

 

logo, o "erro", a "culpa", não é do mdb2, e sim da forma que ele está usando.

Entendeu o ponto ?

 

 

Oque você disse, é o mesmo que dizer: "(O erro está no) |(A culpa é do) PHP".

Compartilhar este post


Link para o post
Compartilhar em outros sites

Essa "checagem" que você fez no construtor, você deveria ter feito no metodo ::open()

 

Isso tecnicamente "resolve" a questão.

Ou então, sei lá, em vez de usar:

$conn = Conn::open();

passar a usar:

$conn = self::$conn;//acho q era isso q quem criou o script queria

 

 

@opiniao_pessoal:

Não gostei do conjunto de classes, e nem da utilização delas.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Também acho que posso mudar o MDB2 de factory para singleton, não é?

 

Obrigado pela ajuda. Vou fazer alguns testes.

 

William, ainda estou no caminho do aprendizado e me bato muito na questão de orientação a objetos. Um dia chego lá.

 

Valeu ela ajuda.

 

abraços.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Tranquilo cara.

 

Use dessa forma aqui:

$conn = self::$conn;

assim você realmente usa a tua verificação. Não precisa checar nada no open não.

Basta não acessa-lo diretamente denovo.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Oi William.

 

Estou tentando fazer da forma que você disse, mas estou recebendo este erro:

Fatal error: Call to a member function query() on a non-object in xxxx.

 

class TSql{

private static $conn;

private function __construct() 
{
	if(empty(self::$conn))
	{
		self::$conn = Conn::open();
	}
	return self::$conn;
}


public function select($sth){
	//$conn = Conn::open();
	$conn = self::$conn;
	$res = $conn->query($sth);

	$ret = $res->fetchRow();
	if(PEAR::isError($ret))
		return false;
	else
		return $ret;
}
}

 

É uma propriedade estática. Não entendo o motivo do erro...

Compartilhar este post


Link para o post
Compartilhar em outros sites

primeiro, construtor nao retorna nada...segundo, você nao vai conseguir usar uma propriedade estatica estando como um objeto comum...eu faria isto

 

class TSql{

       private $conn = null;

       private function __construct() 
       {
               if(is_null($this->conn))
               {
                       $this->conn = Conn::open();
                }

       }


       public function select($sth){


               $res = $this->conn->query($sth);

               $ret = $res->fetchRow();
               if(PEAR::isError($ret))
                       return false;
               else
                       return $ret;
       }
}

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.