Java: Föreläsning 6

Innehåll i föreläsning 6

JDBC

JDBC är Java-sättet att kommunicera med databaser med frågespråket SQL.

Avsnittet Connecting to Databases i Bruce Eckels Thinking in Enterprise Java handlar om JDBC.

Relationsdatabaser och SQL

Orientering. Inte på tentan.

En databas är en samling data, och hanteras av en databashanterare. En relationsdatabas består av en eller flera tabeller, var och en med med noll eller flera rader och en eller flera kolumner. Varje tabell har ett namn. Varje kolumn har ett namn.

Läs mer om databaser här.

Det är själva tabellerna som kallas "relationer" i relationsdatabaser. Det är en vanlig missuppfattning att det är kopplingarna mellan tabellerna som är "relationerna", men så är det inte. (Även om Microsofts översättare trodde det när de översatte Microsoft Access.)

Person

Number Name Telefon
1 Olle 260088
2 Stina 282677
3 Saddam 260088
4 Lotta 174590

Enkel SQL-fråga:

select number, name from person where number < 4
Resultat:

Person

Number Name
1 Olle
2 Stina
3 Saddam

Själva tabellen skapas med ett SQL-kommando:

create table Person
    (number integer,
    name varchar(6),
    telefon varchar(6),
    primary key (number));
Att lägga till en rad:
insert into person values (7, 'Klas', '260088');
Att ändra på en rad:
update person set telefon = '20270' where number = 7;

JDBC-drivrutin

Vi använder en databashanterare som heter Mimer, som kör på en maskin som heter basen.oru.se. Ladda hem Mimers JDBC-drivrutinen från www.mimer.se, eller direkt här. Spara filen som mimjdbc3.jar.

Lägg in själva filen mimjdbc3.jar i CLASSPATH. Linux-exempel:

setenv CLASSPATH $CLASSPATH':'/home/padrone/oru/java/2007-2008-p2/forelasningar/fo-06/mimjdbc3.jar'

JDBC: Uppkoppling och enkel SQL-fråga

Filen PersonTest.java:
import java.sql.*;

public class PersonTest {
    public static void main(String args[]) {
        try {
            Class.forName("com.mimer.jdbc.Driver");
            String url = "jdbc:mimer://bengt:soptipp@basen.oru.se/bilbasen";
            Connection con = DriverManager.getConnection(url);
            Statement stmt = con.createStatement();
            String sql = "select number, name from person where number < 4";
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                int number = rs.getInt(1);
                String name = rs.getString(2);
                System.out.println("Person nummer " + number + " heter " + name + ".");
            }
            rs.close();
            stmt.close();
            con.close();
        }
        catch (SQLException e) {
            while (e != null) {
                System.out.println("SQLException:");
                System.out.println("    SQLState: " + e.getSQLState());
                System.out.println("    Message: " + e.getMessage());
                System.out.println("    ErrorCode: " + e.getErrorCode());
                e = e.getNextException();
            }
        } catch (Exception e) {
            System.out.println("Någon annan exception:");
            e.printStackTrace();
        }
    } // main
} // class PersonTest
Körexempel:
Person nummer 1 heter Olle.
Person nummer 2 heter Stina.
Person nummer 3 heter Saddam.
Körexempel med felaktigt lösenord:
SQLException:
    SQLState: 08004
    Message: Login failure
    ErrorCode: -14006
Körexempel med felstavad SQL-fråga (nummer i stället för number):
SQLException:
    SQLState: 42000
    Message: NUMMER is not a column of an inserted table, updated table or any table identified in a FROM clause
    ErrorCode: -12202

ODBC

Jämför med ODBC i C eller C++: odbc-test-01.c. (Och då ingår inte laddning av drivrutinen och angivande av datakälla, utan det får man göra i kontrollpanelen.)

ODBC:

Uppdatering med JDBC

Filen NewPerson.java:
import java.sql.*;
import java.io.*;

public class NewPerson {
    public static void main(String args[]) {
        BufferedReader reader
            = new BufferedReader(new InputStreamReader(System.in));
        String numberString;
        int number;
        String name;
        String phone;
        try {
            System.out.println("Mata in en ny person.");
            System.out.print("Vad är personens nummer? ");
            numberString = reader.readLine();
            number = Integer.parseInt(numberString);
            System.out.print("Vad är personens namn? ");
            name = reader.readLine();
            System.out.print("Vad är personens telefonnummer? ");
            phone = reader.readLine();
        }
        catch (IOException e) {
            System.out.println("Kunde inte läsa!");
            return;
        }
        catch (NumberFormatException e) {
            System.out.println("Inte ett korrekt tal.");
            return;
        }

        try {
            Class.forName("com.mimer.jdbc.Driver");
            String url = "jdbc:mimer://bengt:soptipp@basen.oru.se/bilbasen";
            Connection con = DriverManager.getConnection(url);
            Statement stmt = con.createStatement();
            String sql = "insert into person values (" + number + ", '" + name + "', '" + phone + "')";
            System.out.println("SQL-kommandot: " + sql);
            int rowCount = stmt.executeUpdate(sql);
            System.out.println(rowCount + " rader ändrade.");
            stmt.close();
            con.close();
        }
        catch (SQLException e) {
            while (e != null) {
                System.out.println("SQLException:");
                System.out.println("    SQLState: " + e.getSQLState());
                System.out.println("    Message: " + e.getMessage());
                System.out.println("    ErrorCode: " + e.getErrorCode());
                e = e.getNextException();
            }
        } catch (Exception e) {
            System.out.println("Någon annan exception:");
            e.printStackTrace();
        }
        System.exit(0);
    } // main
} // class NewPerson
Körexempel 1:
Mata in en ny person.
Vad är personens nummer? 7
Vad är personens namn? Klas
Vad är personens telefonnummer? 260088
SQL-kommandot: insert into person values (7, 'Klas', '260088')
1 rader ändrade.
Körexempel 2:
Mata in en ny person.
Vad är personens nummer? 1
Vad är personens namn? Hanna
Vad är personens telefonnummer? 767610
SQL-kommandot: insert into person values (1, 'Hanna', '767610')
SQLException:
    SQLState: 23000
    Message: PRIMARY KEY constraint violation, attempt to insert duplicate value
    ErrorCode: -10101

JDBC i en applet

Filen MimerApplet.java (provkör den här, om du har en Java-plugin):
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.sql.*;

public class MimerApplet extends JApplet implements ActionListener {
    public void actionPerformed (ActionEvent event) {
        try {
            Class.forName("com.mimer.jdbc.Driver");
            String url = "jdbc:mimer://bengt:soptipp@basen.oru.se/bilbasen";
            Connection con = DriverManager.getConnection(url);
            Statement stmt = con.createStatement();
            String sql = "select number, name from person where number < 4";
            ResultSet rs = stmt.executeQuery(sql);
            text.setText("Personer:\n");
            while (rs.next()) {
                int number = rs.getInt(1);
                String name = rs.getString(2);
                text.append("Person nummer " + number + " heter " + name + ".\n");
            }
            rs.close();
            stmt.close();
            con.close();
        }
        catch (SQLException sqle) {
            while (sqle != null) {
                text.setText("SQLException:\n");
                text.append("    SQLState: " + sqle.getSQLState() + "\n");
                text.append("    Message: " + sqle.getMessage() + "\n");
                text.append("    ErrorCode: " + sqle.getErrorCode() + "\n");
                sqle = sqle.getNextException();
            }
        } catch (Exception exc) {
            text.setText("Other Exception:\n");
            text.append(exc.toString() + "\n");
        }
    } // actionPerformed

    private JTextArea text;

    public void init() {
        Container cp = getContentPane();
        cp.setLayout(new FlowLayout());
        cp.add(new JLabel("En applet som hämtar data om personer"));
        text = new JTextArea("Här kommer personerna att skrivas ut", 4, 30);
        cp.add(new JScrollPane(text));
        JButton runButton = new JButton("Hämta data");
        runButton.addActionListener(this);
        cp.add(runButton);
    } // init

    public static void main(String[] args) {
        MimerApplet applet = new MimerApplet();
        JFrame frame = new JFrame("MimerApplet");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(applet);
        frame.setSize(400, 200);
        applet.init();
        applet.start();
        frame.setVisible(true);
    } // main
} // class MimerApplet
(main-metoden är bara med som ett trick, så man kan köra appleten som en applikation.)

HTML-kod, så man får med JDBC-drivrutinen i filen "mimjdbc3.jar":

<applet archive="mimjdbc3.jar"
        code="MimerApplet.class"
        width="400" height="200">
</applet>
Appleten (i Firefox) före SQL-frågan:
Appleten i Firefox, före SQL-frågan
Appleten efter SQL-frå>gan:
Appleten i Firefox, efter SQL-frågan
Ovanstående är när databasservern och appleten finns på samma dator. Annars:
Säkerhetsstopp i appleten
Hela felmeddelandet:
SQLException:
    SQLState: 08001
    Message: Could not establish connection to server bilbasen on host basen.oru.se using port 1360, java.security.AccessControlException: access denied (java.net.SocketPermission basen.oru.se resolve)
    ErrorCode: -22017
Av säkerhetsskäl får en applet bara göra nätverksuppkopplingar mot samma dator som den själv kommer ifrån.


Thomas Padron-McCarthy (thomas.padron-mccarthy@tech.oru.se), 24 november 2007