Advanced Kittenry - Tietokantasovellusohjeet

Ohjelmointikielen valinta

Tietokantasovellukset kirjoitetaan yleensä joko Javalla tai PHP:llä. Nämä ovat myös tällä hetkellä laitoksen palvelimella tuetut kielet ja niillä tekemiseen pyritään kirjoittamaan ajantasaista dokumentaatiota. Tämä sivu käsittelee lähinnä näitä kahta kieltä. Sovelluksen voi halutessaan kirjoittaa myös esim. Pythonilla tai Rubyllä, kunhan sopii asiasta ohjaajan kanssa.

Etenkin muiden kuin kevyiden web-sovelluskehysten (frameworkkien) käyttäminen vaatii ohjaajan erityisluvan. Tietokanta-abstraktiokerroksia ei myöskään saa käyttää ellei sellaista halua kirjoittaa itse. Esim. Ruby on Rails ei käy.

Miettiessäsi jotain tuettujen kielien ulkopuolista kieltä, pitäydy mielummin kielissä ja kirjastoissa, jotka osaat jo ja joille on olemassa hyvä dokumentaatio. Liian esoteerisillä välineillä tehdyillä töillä on usein tapana jäädä kesken.

Java ja PHP

Perussyntaksiltaan PHP ja Java ovat aika samanlaisia, sillä molemmat ovat perineet syntaksinsa C-kieleltä. PHP on tosin lainannut Perliltä tavan käyttää dollaria $muuttujien nimien edessä. Esimerkiksi luokka Kahvikuppi määriteltäisiin näissä kielissä seuraavasti:

PHP

<?php

class Kahvikuppi {

  /* Luokkamuuttujat */
  private $tekstiKyljessa;
  private $tayttoaste = 0;
  
  /* Konstruktori */
  function __construct($teksti) {
    $this->tekstiKyljessa = $teksti;
  }
  
  /* Metodeja */
  function kaadaKahvia($maara) {
    $this->tayttoaste += $maara;
    if ($this->tayttoaste > 100) {
      throw new Exception("Kahvikuppi valui yli");
    }
  }
  function juoTyhjaksi() {
    $this->tayttoaste = 0;
  }
  function getKahvinMaara() {
    return $this->tayttoaste;
  }
}

Java



class Kahvikuppi {
  
  /* Luokkamuuttujat */
  private String tekstiKyljessa
  private int tayttoaste = 0;

  /* Konstruktori */
  Kahvikuppi(String teksti) { 
    this.tekstiKyljessa = teksti;
  }
  
  /* Metodeja */
  void kaadaKahvia(int maara) {
    tayttoaste += $maara;
    if (tayttoaste > 100) {
      throw new Exception("Kahvikuppi valui yli");
    }
  }
  void juoTyhjaksi() {
    tayttoaste = 0;
  }
  int getKahvinMaara() {
    return tayttoaste;
  }
}

Kuten esimerkeistä voi huomata, kielet ovat normaalissa olio-ohjelmoinnissa melko samanlaisia. Suurin osa eroista on merkintätapaeroja, mutta eräs tärkeä ero esimerkistä näkyy. PHP:ssä ei koskaan määritetä muuttujalle tyyppiä, kuten Javassa tehdään. PHP:ssä muuttujaan voi sijoittaa minkätyyppistä dataa tahansa ja tietotyyppi voi jopa vaihdella ajon aikana. Muuttujia ei PHP:ssä myöskään tarvitse esitellä mitenkään. Esimerkkejä:

PHP

<?php
$luku = 42;
$nimi = "Pertti";
$kuppi = new Kahvikuppi("Pertin kuppi");

//PHP:ssä tämäkin on mahdollista,
//mutta ei suositeltavaa:
$luku = $nimi;

//Seuraavakaan ei vielä kaada ohjelmaa.
//Muuttuja $luku saa arvokseen null
$luku = $nemi;

Java


int luku = 42;
String nimi = "Pertti";
Kahvikuppi kuppi = new Kahvikuppi("Pertin kuppi");

//Seuraavaa riviä on mahdotonta
//saada kääntymään:
luku = nimi;

//Tämäkään ei käänny. Muuttujaa
//nemi ei ole esitelty!
luku = nemi;

Aiheesta lisää informaatiota PHP:n manuaalissa

Javaa koodatessa joutuu kirjoittamaan hieman enemmän, mutta PHP:llä saattaa varsinkin aluksi tehdä tyyppivirheitä, jotka huomaa vasta ajon aikana.

HTML:n käyttö

Toinen huomionarvoinen seikka PHP:tä kirjoittaessa on kielen käyttämät <?php-tägit, jotka aloittavat PHP-koodin. Niiden ulkopuolella olevan tekstin PHP oletuksena tulostaa sellaisenaan. Tämä tekee PHP:n käyttämisestä yksinkertaisten nettisivujen tekemiseen erittäin helppoa:

helloworld.php

<?php
  header("Content-type: text/html;charset=UTF-8");
  $pagetitle =  "Hello World!";
?><!DOCTYPE HTML>
<html>
  <head>
    <title><?php echo $pagetitle; ?></title>
  </head>
  <body>
    <h1><?php echo $pagetitle; ?></h1>
  </body>
</html>

Yllä oleva sivu toimii sellaisenaan, kun osoittaa selaimensa osoitteeseen, jossa helloworld.php-tiedosto sijaitsee. Esim. sivusto.fi/php-sovelluksen/osoite/helloworld.php. Javalla vastaavan tekeminen on hieman monimutkaisempaa ja vaatii Servlet-luokan ja template-tiedoston:

src/java/servlets/HelloWorldServlet.java

package servlets;

import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "HelloWorldServlet", urlPatterns = {"/HelloWorld"})
public class HelloWorldServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.setAttribute("title", "Hello world!");
        
        RequestDispatcher dispatcher = request.getRequestDispatcher("helloworld.jsp");
        dispatcher.forward(request, response);
    }

}

web/helloworld.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
  <head>
    <title>${title}</title>
  </head>
  <body>
    <h1>${title}</h1>
  </body>
</html>

Ylläoleva ohjelma käynnistyy melko lailla PHP-esimerkin tapaan osoitteessa sivusto.fi/java-sovelluksen/osoite/HelloWorld. Tässä käytetty JSP-tiedostoformaatti on Javan-vastaus PHP:n suoraviivaiselle tavalle käsitellä HTML:n tulostusta ja sitä on varsin yksinkertaista käyttää.

Itse Java-ohjelmakoodi sensijaan on aika monimutkaista ja käyttää taustalla suurta määrää Javan kirjastoja. Tätä ei kovin moni jaksaisi kirjoittaa, siksi ylläolevasta koodista suurin osa onkin NetBeansin autogeneroimaa, eikä kaikkea onneksi tarvitse kirjoittaa itse.

PHP on kielenä optimoitu nopeaan nettisivustojen kasaamiseen. Suuremmilla sivustoilla ja monimutkaisempia kehyksiä käytettäessä PHP-koodikin alkaa muistuttaa yllä olevaa Java-koodia ja pitenee ja monimutkaistuu merkittävästi. Yleisenä nyrkkisääntönä kuitenkin on, että pienikokoisempiin web-projekteihin - esimerkiksi tietokantasovelluksiin - Java-koodia joutuu kirjoittamaan enemmän kuin vastaaviin PHP:llä tehtyihin sovelluksiin.

Tietokannan käyttö

Sekä PHP että Java hoitavat tietokannan käytön oliopohjaisesti tavalla, joka mahdollistaa kielen sisäisten muuttujien upottamisen SQL-lausekkeisiin helposti ja tietoturvallisesti.

tietokanta.php

<?php
  //Otetaan yhteys mysql-tietokantaan
  $yhteys = new PDO("mysql:host=localhost;dbname=tietokannan_nimi", "kayttaja", "salasana");

  //Suoritetaan sql-kysely. Haetaan täysi-ikäiset Lehtoset tietokannasta
  $sql = "SELECT id, nimi, osoite FROM kayttajat WHERE ika >= ? and sukunimi = ?";
  $kysely = $yhteys->prepare($sql);
  $tulokset = $kysely->execute(array(18,"Lehtonen"));

  //Tulostetaan tietoja löydetyistä käyttäjistä
  while($rivi = $tulokset->fetchObject()) {
    echo "Käyttäjän $rivi->etunimi $rivi->sukunimi ikä on $rivi->ika";
  }

  //PHP sulkee yhteydet ja resurssit automaattisesti
  //suorituksen päätteeksi

tietokanta.java

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

Connection yhteys = null;
PreparedStatement kysely = null;
ResultSet tulokset = null;

class Tietokanta {

  public static void teeAsioitaKannalla() throws Exception {
    try {
      //Haetaan context-xml-tiedostosta tietokannan yhteystiedot
      //HUOM! Tämä esimerkki ei toimi sellaisenaan ilman Tomcat-palvelinta!
      Context ctx = new InitialContext();
      DataSource yhteysVarasto = (DataSource) ctx.lookup("java:/comp/env/jdbc/tietokanta");

      //Otetaan yhteys tietokantaan
      yhteys = yhteysVarasto.getConnection();

      //Suoritetaan sql-kysely. Haetaan täysi-ikäiset Lehtoset tietokannasta
      String sql = "SELECT etunimi, sukunimi, ika FROM kayttajat WHERE ika >= ? and sukunimi = ?";
      kysely = yhteys.prepareStatement(sql);
      kysely.setInteger(1, 18);
      kysely.setString(2, "Lehtonen");
      tulokset = kysely.executeQuery();

      //Tulostetaan tietoja löydetyistä käyttäjistä
      while(tulokset.next()) {
        String nimi = tulokset.getString("etunimi") + " " +tulokset.getString("sukunimi");
        int ika = tulokset.getString("ika");
        System.out.println("Käyttäjän "+nimi+" ikä on "+ika);
      }

    } catch (Exception e) {
      throw e;
    } finally {
      //Suljetaan lopulta kaikki avatut resurssit
      try { tulokset.close(); } catch (Exception e) {  }
      try { kysely.close(); } catch (Exception e) {  }
      try { yhteys.close(); } catch (Exception e) {  }
    }
  }
}

Yllä oleva Java-koodi hakee tietokannan tiedot xml-tiedostosta:

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/Kissalista-java">
    <Resource name="jdbc/tietokanta" auth="Container"
        type="javax.sql.DataSource" removeAbandoned="true"
        removeAbandonedTimeout="30" maxActive="100"
        maxIdle="30" maxWait="10000" username="tunnus"
        password="salasana"
        driverClassName="org.postgresql.Driver"
        url="jdbc:postgresql://localhost/tietokannan_nimi" />
</Context>

PHP on tässäkin tapauksessa merkittävästi vähäsanaisempi. Taitava koodari lyhentää yllä olevasta esimerkistä toistuvat koodinpätkät kuitenkin yleiskäyttöisiin metodeihin, jolloin lopullisessa käytössä eri kielten tapa käsitellä tietokantaa on lähestulkoon yhtä monisanainen. Lisäksi Javan versiossa 7 resurssien sulkemisesta on tehty automaattisempaa. Valitettavasti tosin laitoksen palvelimilla oleva versio ei ole vielä ajan tasalla.

Yhteenveto

Kumpaa sitten kannattaa käyttää? Sitä mikä tuntuu kotoisimmalta ja luonnollisemmalta. Tätä nykyä suurin osa valitsee PHP:n sen keveyden takia, mutta kumpaankin kieleen on tarjolla varsin mallikkaat välineistöt tietokantasovelluksen tekemiseen.

Ominaisuus Java PHP
Ajotapa Käännetään ennen ajoa Tulkitaan ajonaikaisesti
Tyyppijärjestelmä Vahva tyypitys Heikko tyypitys
HTML:n tuottaminen JSP-kielellä Suoraan PHP-koodin sisällä
Konfigurointi Lukuisilla XML-tiedostoilla Monia tapoja. Mahdollista suoraan koodissa.

Voit tutustua myös Sami Saadan tekemiin esimerkkisovelluksiin PHP ja Java-kielellä. Bonuksena samasta aiheesta on olemassa myös hyvin tiivis Ruby-toteutus Sinatra-kehyksellä tehtynä.

PHP:n syntaksista voi myös lukea lisää lyhyestä PHP-syntaksioppaasta.

Linkkejä:

Seuraavaksi:

Kun olet valinnut aiheesi ja mieleisen ohjelmointikielen, vilkaise tietokannan valitsemista.