Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: PHP, PDO ja MySQL

xxmss [31.01.2019 22:30:02]

#

Moi! Minulla on hieman ongelmia MySQL-kannan yhteyksien kanssa. Käytössä on PDO, mutta en ole varma, olenko ymmärtänyt sen toimintapaa oikein vai pitäisikö minun lisätä koodia useaan eri paikkaan.

Tiedosto hae_ottelut.php:

require "otteluohjelma.php";

$otteluohjelma = new Otteluohjelma();

$kaavio_id = 1;

$ottelut = $otteluohjelma->hae_ottelut($kaavio_id);

print "<pre>";
print_r($ottelut);
print "</pre>";

Tiedosto otteluohjelma.php:

class Tietokanta
{
  protected $yhteys;

  function __construct()
  {
    try
    {
      $this->yhteys = new PDO("mysql:host=localhost;dbname=testikanta", "testitunnus", "testisalasana");
      $this->yhteys->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
      $this->yhteys->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      $this->yhteys->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
      $this->yhteys->exec("SET NAMES latin1");
    }
    catch (PDOException $e)
    {
      error_log($e);
    }
  }
}

class Otteluohjelma extends Tietokanta
{
  protected $yhteys;

  function __construct()
  {
    parent::__construct();
  }

  function hae_ottelut($kaavio_id)
  {
    $palautettava = array();

    try
    {
      $kysely = $this->yhteys->prepare("SELECT ottelunumero FROM ottelut WHERE kaavio_id = ?");
      $kysely->bindValue(1, intval($kaavio_id), PDO::PARAM_INT);
      $kysely->execute();

      while($rivi = $kysely->fetch(PDO::FETCH_ASSOC))
      {
        $palautettava['ottelut'][$rivi['ottelunumero']] = "k";
      }
    }
    catch(PDOException $e)
    {
      error_log($e);
    }

    return $palautettava;
  }
}

Pitäisikö tietokantayhteys katkaista jossain jotenkin näin ja jos, niin missä?

$kysely = null;
$yhteys = null;

Olen käsittänyt aiemmin, että noita kahta riviä ei tarvittaisi vaan tietokantayhteys katkeaisi automaattisesti PHP-tiedoston suorituksen loputtua eikä muistiin jäisi mitään ylimääräistä, mutta nyt en ole enää varma asiasta.

Minulla on ollut ongelmia Apache-palvelimella liiallisen I/O Usagen kanssa ja myös Entry Processes on ollut liiallinen. Mietinkin, voisinko tietokannan kanssa toimia fiksummin, jotta palvelin ei kuormittuisi turhaan tietokantayhteyksien takia. Neuvot ovat tervetulleita, kiitos.

Metabolix [31.01.2019 23:28:56]

#

Tietokantaa tosiaan ei tarvitse erikseen sulkea. Vika on jossain muualla.

Ongelmasi voi olla siinä, että nyt avaat uuden tietokantayhteyden jokaiselle Tietokanta-luokasta periyttämällesi oliolle. Esimerkiksi jokaiselle Otteluohjelma-oliolle luodaan tässä uusi tietokantayhteys. Yleensä järkevää on avata tietokanta yhdessä paikassa ja käyttää samaa yhteyttä koko sivustolla. Tämän voi tehdä monella tavalla ja "oikein" ja "väärin", mutta tyypillisesti tähän käytetään joko globaalia muuttujaa tai staattista ominaisuutta. Omassa mallissasi tämä onnistuisi vaikka tähän tapaan:

final class YhteinenTietokanta {
	private static $yhteys;
	public static function yhteys() {
		if (!self::$yhteys) {
			self::$yhteys = new PDO();
		}
		return self::$yhteys;
	}
}

class Otteluohjelma {
	function __construct() {
		$this->yhteys = YhteinenTietokanta::yhteys();
	}
}

Sivuhuomiona, kannattaa opetella käyttämään UTF-8-merkistöä latin-1:n (ISO-8859-1:n) sijaan, koska nykymaailmassa ei vain pärjää noin rajoittuneella merkistöllä.

xxmss [01.02.2019 10:58:26]

#

Tarkoittaako tuo Metabolixin kirjoittama sitten sitä, että jos minulla on tällaista koodia tiedostossa hae_ottelut.php...

require "otteluohjelma.php";

$otteluohjelma = new Otteluohjelma();

$kaavio_id = 1;
$pelipaikka_id = 10;

$ottelut = $otteluohjelma->hae_ottelut($kaavio_id);
$pelipaikan_ottelut = $otteluohjelma->hae_pelipaikan_ottelut($kaavio_id, $pelipaikka_id);

print "<pre>";
print_r($ottelut);
print "</pre>";

print "<pre>";
print_r($pelipaikan_ottelut);
print "</pre>";

...ja tällaista koodia tiedostossa otteluohjelma.php...

class Tietokanta
{
  protected $yhteys;

  function __construct()
  {
    try
    {
      $this->yhteys = new PDO("mysql:host=localhost;dbname=testikanta", "testitunnus", "testisalasana");
      $this->yhteys->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
      $this->yhteys->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      $this->yhteys->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
      $this->yhteys->exec("SET NAMES latin1");
    }
    catch (PDOException $e)
    {
      error_log($e);
    }
  }
}

class Otteluohjelma extends Tietokanta
{
  protected $yhteys;

  function __construct()
  {
    parent::__construct();
  }

  function hae_ottelut($kaavio_id)
  {
    $palautettava = array();

    try
    {
      $kysely = $this->yhteys->prepare("SELECT ottelunumero FROM ottelut WHERE kaavio_id = ?");
      $kysely->bindValue(1, intval($kaavio_id), PDO::PARAM_INT);
      $kysely->execute();

      while($rivi = $kysely->fetch(PDO::FETCH_ASSOC))
      {
        $palautettava['ottelut'][$rivi['ottelunumero']] = "k";
      }
    }
    catch(PDOException $e)
    {
      error_log($e);
    }

    return $palautettava;
  }

  function hae_pelipaikan_ottelut($kaavio_id, $pelipaikka_id)
  {
    $palautettava = array();

    try
    {
      $kysely = $this->yhteys->prepare("SELECT ottelunumero FROM ottelut WHERE kaavio_id = ? AND pelipaikka_id = ?");
      $kysely->bindValue(1, intval($kaavio_id), PDO::PARAM_INT);
      $kysely->bindValue(2, intval($pelipaikka_id), PDO::PARAM_INT);
      $kysely->execute();

      while($rivi = $kysely->fetch(PDO::FETCH_ASSOC))
      {
        $palautettava['ottelut'][$rivi['ottelunumero']] = "k";
      }
    }
    catch(PDOException $e)
    {
      error_log($e);
    }

    return $palautettava;
  }
}

...niin muodostuuko tässä kaksi yhtäaikaista tietokantayhteyttä, vaikka voisin hoitaa asian vain yhdellä tietokantayhteydellä?

Metabolix [03.02.2019 18:09:03]

#

Muodostuu yksi yhteys, koska luot yhden Tietokanta-olion (Otteluohjelma-olion). Sen sijaan jos luot samalla sivulla monta Otteluohjelma-oliota tai luot vaikkapa Otteluohjelma-olion ja samantapaisen OttelunTiedot-olion, yhteyksiä tulisi useampi. Tämän pitäisi olla aika helppo hahmottaa.

Joka tapauksessa ei ole järkevää käyttää periytymistä noin, koska oikeasti otteluohjelma ei ole tietokantayhteys. Eli kuten jo sanoin, olisi loogista luoda tietokantayhteys erikseen ja välittää se jollain muulla tavalla sitä käyttäville luokille.

Varsinaisen ongelmasi syitä voi vain arvailla, kun olet antanut parikymmentä riviä asian kannalta melko epäolennaista koodia. Oikeastaan jää epäselväksi jopa se, onko kyseessä todellinen ongelma vai oletko vain säikähtänyt jotain lukuja.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta