# Art des Datenbankzugriffs



## Guest (8. Sep 2005)

Hallo Leute,           die Frage am Schluss

ich schreibe ein umfangreicheres Programm und habe keine Informatikerausbildung. Daher weiss ich nicht, ob die Art und Weise wie ich den Zugriff auf meine Interbase-Datenbank handle grundsätzlich richtig ist.

So habe ich es gemacht:

1) Verbindung zur Datenbank in einer eigenen Klasse.

```
import java.sql.*;
import javax.swing.JOptionPane;

public class DBANSCon {

  static final String DRIVER = "interbase.interclient.Driver";
  static final String URL = "jdbc:interbase://localhost/C:/Dokumente und Einstellungen/GDB/";


  Connection con;
  Statement stmt, stmt1, stmt2, stmt3;
  DatabaseMetaData dmd;
  ResultSet rs, rs1, rs2;

  public DBANSCon() {
    try {
      DBEntry();
    }
    catch (ClassNotFoundException ex) {
      ex.printStackTrace();
    }
    catch (SQLException ex) {
      ex.printStackTrace();
    }
  }

  private void DBEntry() throws ClassNotFoundException, SQLException {
      Class.forName(DRIVER);
      con = DriverManager.getConnection(URL + "DBGMUNDENVORCHDORF.gdb", "sysdba", "masterkey");

      con.setAutoCommit(true);
      if (con.isClosed() == true) {
        int selection = JOptionPane.showConfirmDialog(null, "Kein Datenbankzugriff möglich!  ",
            "Information", JOptionPane.DEFAULT_OPTION,
            JOptionPane.INFORMATION_MESSAGE);
        System.exit(0);
      }
      stmt = con.createStatement();
      stmt1 = con.createStatement();
      stmt2 = con.createStatement();
      stmt3 = con.createStatement();
      dmd = con.getMetaData();
    }
}
```

2) In der static void main so eine Art globale Variablen angelegt.

```
DBANSCon = new DBANSCon();
```

3) Überall dort wo ich eine Datenbankverbindung benötige wie folgt aufgerufen.

```
MainProgram.DBANSCon.rs = MainProgram.DBANSCon.stmt.executeQuery("selectabfrage");
```

-MainProgram heißt die Klasse in der die static void main steht.

Das wäre mein Ansatz. Indem ich aber nirgendwo schliesse (weder rs, noch stmt's, noch con's) wirft es mir von Zeit zu Zeit Connection errors. 
Daher die Frage: Ist der Ansatz richtig?????

Danke für eure Hilfe
Juergen


----------



## Roar (8. Sep 2005)

ich find das design irgendwie nicht so gut, da:
MainProgram.DBANSCon.rs = MainProgram.DBANSCon.stmt.executeQuery("selectabfrage"); 
geh ich mal davon aus, dass die variable in MainProgram statisch und öffentlich ist? das sieht nich schön aus. sorge lieber dafür, dass alle klassen, die die dbconnection brauchen, die instanz von CBANSCon (der name gefällt mir auch nich ^^) übergeben bekommen, oder mach die klasse als singleton.
außerdem wärs noch besser, du würdest alle sachen die mit datenbankabfragen zu tun haben irgendwo abkapseln. das versuchst du vielleicht schon, aber so wirklich abgekapselt ist das nicht, wenn du aus einer anderen klasse raus die sql queries ausführst. mach lieber methoden in deiner datenbankklasse, die die abfragen ausführen und dir schon deine benötigte datenstruktur zurückgeben.


----------



## Guest (8. Sep 2005)

Du hast recht - die Variablen sind statisch und öffentlich.
Methoden in die DB-Klasse reinsetzen hört sich verdammt gut an, aber da gibt es, denke ich, Probleme.
Wenn ich es richtig verstehe soll ich aus jener Klasse, aus der ich die Datenbankabfrage starte die Klasse DBANSCon instanzieren (der Name ist in Ordnung) und die selectabfrage and die DBANSCon übergeben!?
Wenn denn das so ist - Was passiert wenn diese eine Methode von mehreren Klassen parallel aufgerufen wird?
Bekomme ich da nicht ein ZeitProblem?


----------



## Guest (8. Sep 2005)

Und zusätzlich mache ich oft Auswertungen in der 

```
while (MainProgram.DBANSCon.rs.next()) {
}
```

Schleife. Das funktioniert dann auch nicht mehr?

Danke


----------



## Roar (8. Sep 2005)

ne, du instantiierst Con nur einmal, meinetwegen im MainProgram und übergibst die instanz dann an deine anderen klassen. eine select anfrage übergeben ist eben nicht so gut. die select anfrage sollte sich die Con Klasse selber zusammenbaun und ausführen. die instanzvariablen von Con sollten übrigens besser private sein, wobei ich auch nicht verstehe warum du die variablen da hast, denn wenn du zukünftig eh nicht mehr drauf zugreifst kannst du sie auch als lokale variablen benutzen.



> Wenn denn das so ist - Was passiert wenn diese eine Methode von mehreren Klassen parallel aufgerufen wird?


von mehreren klassen parallel geht nicht. wenn du mehrere threads hast schon. was verstehst du unter einem zeit problem?

so, nu muss ich aber in die schule


----------



## KSG9|sebastian (8. Sep 2005)

Ich würde die DB-Instanz nicht übergeben, sondern das ganze als Singleton laufen lassen


```
class Db{
   private static Db instance = null;
   private Db(){  //doSomething }
   public static Db getInstance(){
      if(instance == null)
         instance = new Db();
      return instance;
   }
}
```

Und dann in jeder Klasse in der Db genutzt wird:


```
Db db = Db.getInstance();
```



Und dieses Main.DBABXYZ.rs.next ist schlechtes Design, dafür verwendet man getter/setter, Singletons oder andere Patterns.
Desweiteren sollte man nicht aus jeder Klasse DB-Abfragen abfeuern können, deshalb: 

Bau in die DB-Klasse Methoden ein (selectMitglieder u.s.w.) und mach ALLE anderen Methoden private. 
Und vor allem KEINEN getter für das ResultSet bzw. die Connection, Statement u.s.w.


----------



## juergenerwin (9. Sep 2005)

Hallo sebastian,

dein Vorschlag gefällt mir. Ich habe zwar noch keine Ahnung was Singletons sind, aber das kann ich mir ja ansehen. Des Verständnisses halber noch eine Frage (mir gefällt die Struktur ja selbst nicht):
So wie ich das verstehe kann ich mit dem Singleton die Verbindung zur DB herstellen. Dein Vorschlag ist nun alle select-Abfragen in dieser Singleton-Klasse (oder was das auch ist) in Mehtoden zusammenfassen und diese Methoden an Ort und Stelle aufzurufen.
Das hört sich gut an, kann ich aber nicht umsetzen. Und zwar deshalb weil ich die jeweiligen Ergebnismengen oft auswerten muss. Das würde für mich bedeuten ich muss jede Ergebnismenge in ein ArrayList schreiben und dieses dann auswerten. Das scheint mir doch ein bisschen umständlich zu sein. Es muss noch was einfacheres geben.

Ich zeig die mal ein Beispiel eines solchen Aswertevorganges:

```
boolean addAktuelleKurse = false;
    try {
      aktuelleKurseClone = (ArrayList)getAktuelleKurse().clone();
      MainProgram.DBANSCon.rs = MainProgram.DBANSCon.stmt.executeQuery(
          "select kurs_id, fahrtnummer " +
          "from tagesfahrplan t, tf_status s, jf_kurs k " +
          "where (gueltig_am = '" + MainProgram.Datum.getAktuellesDatum() +  "') " +
          "  and (t.tagesfahrplan_id = s.tagesfahrplan_id) " +
          "  and ((status = 1) or (status = 2)) " +
          "  and (k.kurs_id = s.kurs_id)");
      while (MainProgram.DBANSCon.rs.next()) {
        //Kontrolle, ob neuer Kurs hinzugekommen, oder alte entfernt worden ist.
        if (getAktuelleKurse().size() != 0) {
          for (int i = 0; i < getAktuelleKurse().size(); i++) {
            String kurs_id = MainProgram.DBANSCon.rs.getString("kurs_id");
            addAktuelleKurse = false;
            if (((Kurs)getAktuelleKurse().get(i)).getKursID().equals(kurs_id)) {
              //Jeder in der Datenbank aktuelle Kurs wird mit dem Inhalt der
              //Arraylist verglichen. Sobald eine Übereinstimmung auftritt -
              //ergo der Kurs bereits in der Arraylist vorhanden ist - wird
              //dieser nicht mehr in die Arraylist aufgenommen!
              addAktuelleKurse = false;
              break;
            }
            else {
              addAktuelleKurse = true;
            }
          }
          if (addAktuelleKurse == true) {
            aktuelleKurse.add(new Kurs(MainProgram.DBANSCon.rs.getString("kurs_id")));
            System.out.println("Kurs wird hinzugefügt!");
//            ZeitTelegramm zt = new ZeitTelegramm(getAktuelleKurse());
          }
          else {
//            System.out.println("Der Kurs ist bereits vorhanden!");
          }
        }
        else {
          aktuelleKurse.add(new Kurs(MainProgram.DBANSCon.rs.getString("kurs_id")));
        }
      }
    }
    catch (SQLException ex) {
      ex.printStackTrace();
    }
```

Solche Konstrukte habe ich vielfach in meinem Programm. Ich hatte eben noch sehr, sehr wenig von Programmierung als ich damit betraut wurde, daher fehlt die Struktur. Das muss ich nun ausbaden.
Danke für den Tipp mit den Singletons!


----------

