20.3. Samlet eksempel

Det er en god idé at indkapsle databasekommunikationen ét sted, f.eks. i en klasse, sådan at resten af programmet kan fungere, selvom databasens adresse eller struktur skulle ændre sig.

Ofte vil man have en klasse per tabel i databasen, sådan at et objekt kommer til at svare til en række [1]:

public class Kunde
{
  String navn;
  double kredit;

  public Kunde(String n, double k)
  {
    navn = n;
    kredit = k;
  }

  public String toString()
  {
    return navn+": "+kredit+" kr.";
  }
}

Klassen, der varetager forbindelsen til databasen, bør have metoder, der svarer til de kommandoer og forespørgsler, resten af programmet har brug for. Hvis databasen ændrer sig, er det kun denne klasse, der skal rettes.

import java.sql.*;
import java.util.*;

public class Databaseforbindelse
{
  private Connection forb;
  private Statement stmt;

  public Databaseforbindelse() throws Exception
  {
    Class.forName("oracle.jdbc.driver.OracleDriver");
    Connection forb = DriverManager.getConnection(
      "jdbc:oracle:thin:@oracle.cv.ihk.dk:1521:student","stuk1001","hemli'");
    stmt = forb.createStatement();
  }

  public void sletAlleData() throws SQLException
  {
    stmt.execute("truncate table KUNDER");
  }

  public void opretTestdata() throws SQLException
  {
    try { // hvis tabellen allerede eksisterer opstår der en SQL-udtagelse
      stmt.executeUpdate(
        "create table KUNDER (NAVN varchar(32), KREDIT float)" );
    } catch (SQLException e) {
      System.out.println("Kunne ikke oprette tabel: "+e);
    }
    stmt.executeUpdate("insert into KUNDER values('Jacob', -1799)");
    stmt.executeUpdate("insert into KUNDER values('Brian', 0)");
  }

  public void indsæt(Kunde k) throws SQLException
  {
    stmt.executeUpdate("insert into KUNDER (NAVN,KREDIT) values('" 
      + k.navn + "', " + k.kredit + ")");
  }

  public Vector hentAlle() throws SQLException
  {
    Vector alle = new Vector();
    ResultSet rs = stmt.executeQuery("select NAVN, KREDIT from KUNDER");
    while (rs.next())
    {
      Kunde k = new Kunde( rs.getString("NAVN"), rs.getDouble("KREDIT"));
      alle.addElement(k);
    }
    return alle;
  }
}

Klassen lader kalderen om at håndtere de mulige undtagelser. Det er fornuftigt, da det også er kalderen, der skal fortælle fejlen til brugeren og evt. beslutte, om programmet skal afbrydes.

Her er et program, der bruger Databaseforbindelse. Først opretter det forbindelsen og henter alle poster, dernæst sletter det alt og indsætter en enkelt post. Hvis der opstår en fejl, udskrives "Problem med database", og programmet afbrydes.

import java.util.*;

public class BenytDatabaseforbindelse
{
  public static void main(String arg[])
  {
    try {
      Databaseforbindelse dbf = new Databaseforbindelse();

      dbf.opretTestdata(); // fjern hvis tabellen allerede findes
      Vector  v = dbf.hentAlle();
      System.out.println("Alle data: "+v);
      dbf.sletAlleData();

      dbf.indsæt( new Kunde("Kurt",1000) );
      System.out.println("Alle data nu: "+ dbf.hentAlle());

    } catch(Exception e) {
      System.out.println("Problem med database: "+e);
      e.printStackTrace();
    }
  }
}

Resultatet bliver:

Alle data: [Jacob: -1799.0 kr., Brian: 0.0 kr.]
Alle data nu: [Kurt: 1000.0 kr.]

Slutbemærkning:

[1]

Det kommer lidt an på, i hvor høj grad basen er normaliseret.