# Aufteilung von Verbindungsaufbau & SQL Statements sinnvo



## JavaNewb (17. Jun 2006)

Hallo zusammen! 

Ich bin ganz am Anfang meines kleinen Java Projektes. Ich habe eine Access-DB und muss ein Klausuranmeldungsprogram erstellen. 

Im Prinzip weiss ich wie die JDBC DB Anbindung funktioniert (verbinden, absetzen SQL Statement, Auswerten, schließen SQL Statement, Verbindung beenden). 

Jetzt meine Frage  ???:L    :

Ist es sinnvoll eine Klasse zu haben die REIN fuer den Verbindungsaufbau zuständig ist und dann eben weitere Klassen die nur die SQL Statements abarbeiten?  Ich frage mich ob ich nicht in allen Klassen mit den SQL Statements den Verbindungsaufbau durchführen muss? Oder reicht es schon von der "DB Verbindungsklasse" irgendwie durch  (z.B. des Konstruktors der die Verbindung vornimmt) zu erben?? Oder doch einfach alles in eine DB-Klasse stecken und über einzelne Methoden die SQL Statements abbarbeiten?? 

also:   Datenbankklasse:                         Verbindung aufbauen
          listeStudent:                                 soll alle Studenten aus der DB auslesen und anzeigen
          listeKlausuranmeldungen:              zeige Studenten und ihre Anmeldungen an
          gesamtZahlKlausuranmeldungen:   zeige Anzahl Klausuranmeldungen


---------------------------
Man bin ich verwirrt....


Vielen Dank für eure Hilfe und Grüße


Marko


----------



## Timmah (17. Jun 2006)

Ja, also bau die Verbindung einmal auf, und hole dir dann immer in der Klasse, die für die SQL-Statements zuständig ist, dieses Connection-Objekt.

Ich habe das meistens über eine Klasse "Verbindung" gemacht, in der ich die statische Methode getConnection(), verbinden() und trennen() habe.

So ist das eigentlich recht ordentlich handzuhaben.


----------



## Guest (17. Jun 2006)

Hi Timmah! 

Habe schonmal versucht selbst rumzuwursteln, scheint auch ganz gut zu funktionieren mit dem Trennen. Habe mal eine Verbindungsklasse gemacht und schonmal eine um eine DB Tabelle ueber SQL auszulesen. Ich stell sie mal hier rein, vielleicht kann sie ja als nette Vorlage dienen oder vielleicht hat auch jemand einen Verbesserungsvorschlag  


```
package Datenbankklassen;

import java.sql.*;

public class DatenbankKlasse {
	
    
	      /**
   * Stellt die Verbindung zur Datenbank her
   */
        protected Connection con = null;
	protected String url = "jdbc:odbc:klausuranmeldung";
	protected String treiber = "sun.jdbc.odbc.JdbcOdbcDriver";
	
        
        /**
   * Konstruktor
   */
	public DatenbankKlasse(){
                // Initialisierung der Datenbankverbindung
		try {
			Class.forName(treiber);
			con = DriverManager.getConnection(url);
		}
		catch (Exception e) {
			System.out.println("Verbindung zu \"" + url +"\" konnte nicht hergestellt werden.");
			System.exit(1);
		}       
	}
	
        /**
   * Schliesst die Verbindung.
   */
        public void close() {
                try {
                     con.close();
                    } 
                catch (SQLException e) {
                }
        }	
}
```


```
package Datenbankklassen;

import java.sql.*;

public class StudentenAnzeigen extends DatenbankKlasse {
    
    Statement stmt = null; 
    ResultSet rs = null;  
    String name;
    int matrikelnr;
    
    /** Creates a new instance of StudentenAnzeigen */
    public StudentenAnzeigen() {
        super();
    }
    
    public void zeigeStudenten()
    {
        try
        {
            stmt = con.createStatement();
            rs = stmt.executeQuery ("SELECT MatrikelNr, Name FROM studenten");
            
            System.out.println ("MatrikelNr  Name        ");
            System.out.println ("------------------------");
            
            
            while (rs.next())
            {
                matrikelnr = rs.getInt (1);
                name = rs.getString (2);
                System.out.println(matrikelnr+ "         " + name);
            }
            
            stmt.close();
            
            con.close();
        }
        
        catch (Exception ex)
        {
            System.out.println("Exception: " + ex.getMessage());
            
        }
    }
    
    public static void main(String[] args)
    {
        StudentenAnzeigen einStudent = new StudentenAnzeigen();
        einStudent.zeigeStudenten();
    }
      
}
```



So müsste das doch passen, oder??  :roll:


----------



## Guest (17. Jun 2006)

hmm.. eine Frage hab ich dann doch noch.. zwecks Einordnung: 

Ich möchte das Projekt einigermassen sauber in Dialogschicht, Fachkonzept- und Datenbankschicht unterteilen.. 
Gehört die Klasse StudentenAnzeigen von der Logik eher zur Datenbank- oder zur Fachkonzeptschicht?


----------



## Timmah (17. Jun 2006)

Bin ich Programmierer oder Planer? 

Keine Ahnung, such dir was aus...


----------



## SebiB90 (17. Jun 2006)

Timmah hat gesagt.:
			
		

> Bin ich Programmierer oder Planer?


am besten wäre es wenn du beides wärst


----------



## Timmah (17. Jun 2006)

SebiB90 hat gesagt.:
			
		

> Timmah hat gesagt.:
> 
> 
> 
> ...



Weiß ich doch   :applaus:


----------



## Guest (20. Jun 2006)

Hi auch wieder  

Sodele, hab mit meinem Prof gesprochen.. er war wenig begeistert davon dass die Klasse StudentenAnzeigen von DatenbankKlasse erbt.. 

Das heisst ich muss folgende Aufteilung machen:

1) DatenbankKlasse ist lediglich fuer die Connection der Datenbank zuständig 
2) In der (Fach)klasse StudentenAnzeigen soll lediglich das SQL Statement ausgeführt werden


Hier die Datenbankklasse für den Verbindungsaufbau: 


```
import java.sql.*;

public class DatenbankKlasse {
	
    
	      /**
   * Stellt die Verbindung zur Datenbank her
   */
        private Connection con = null;
	private String url = "jdbc:odbc:Klausurverwaltung";
	private String treiber = "sun.jdbc.odbc.JdbcOdbcDriver";
	
        
        /**
   * Konstruktor
   */
	public DatenbankKlasse(){     
	}
	
            /**
   * Öffnet die Verbindung.
   */  
        public void open() {
            try {
			Class.forName(treiber);
			con = DriverManager.getConnection(url);
                        System.out.println("Anbindung erfolgreich!");
                        
		}
		catch (Exception e) {
			System.out.println("Verbindung zu \"" + url +"\" konnte nicht hergestellt werden.");
			System.exit(1);
		}       
        }
                
        /**
   * Schliesst die Verbindung.
   */
        public void close() {
                try {
                     con.close();
                    } 
                catch (SQLException e) {
                }
        }
        

}
```


Und hier die Klasse zeigeStudenten


```
import java.sql.*;

public class zeigeStudent  {
      
    //Konstruktor, erbt von der Vaterklasse den Verbindungsaufbau
    public zeigeStudent() { 
    }
    
        // Methode die das SQL Statement implementiert
    public String zeigStudent()
    {        
                
                String ausgabe = "";
                Connection con = null;
                Statement stmt; 
                ResultSet rs;  
                int matrikelnr;
                String name;
                String vorname;
                String geburtsdatum;
                String adresse;
                String geschlecht;
                String telefon;   
        try
        {
  
            stmt = con.createStatement();
            rs = stmt.executeQuery ("SELECT * FROM Student ORDER BY Name");

            while (rs.next())
            {
                ausgabe = ausgabe + rs.getString(1) + "\t" + rs.getString(2) + "\t" + "\t" + rs.getString(3) + "\t" + rs.getString(4) + rs.getString(5) + "\t" + rs.getString(6) + "\t" + rs.getString(7) + "\n";
                System.out.println(ausgabe);
            }
            
            // Schliessen des Statements
            stmt.close();
            
            //Schliessen der Verbindung
            con.close();
        }
        
        catch (Exception ex)
        {
            System.out.println("Exception: " + ex.getMessage());  
        }
  
        return ausgabe;
       
    }

    public static void main (String[] args) {
        DatenbankKlasse eineVerbindung = new DatenbankKlasse();
        eineVerbindung.open();
        
        zeigeStudent einStudent = new zeigeStudent();
        einStudent.zeigStudent();
    }
       
 
}
```


Die main - methode ist nur als Test gedacht um zu sehen ob er was zurückgibt. Die Anbindung meldet er erfolgreich, doch statt den Daten aus der DB kommt "Exception: null" 

ich denke es liegt an der Connection con  oder so, das ich in der Klasse zeigeStudenten neu initialisier... müsste ich "con" direkt aus der Datenbankklasse beziehen, und falls ja, wie?? 

Mach hier schon seit 3 Stunden rum, bald ist Fussballspiel... aah bitte helfen


----------



## Guest (21. Jun 2006)

hat denn keiner ne Idee?????  :bahnhof:


----------



## Guest (22. Jun 2006)

wirklich keiner??


----------



## Murray (22. Jun 2006)

Bau in die Datenbankklasse eine get-Methode ein:


```
public Connection getConnection() {
  return con;
}
```

Für Student#zeigStudent spendierst Du eine Paramer Datenbankklasse dbk; die lokale Variable con kommt weg.


```
public String zeigStudent( Datenbankklasse dbk)
    {       
               
                String ausgabe = "";
                Statement stmt;
                ResultSet rs; 
                int matrikelnr;
                String name;
                String vorname;
                String geburtsdatum;
                String adresse;
                String geschlecht;
                String telefon;   
        try
        {
 
            stmt = dbk.getConnection().createStatement();
            rs = stmt.executeQuery ("SELECT * FROM Student ORDER BY Name");

            while (rs.next())
            {
                ausgabe = ausgabe + rs.getString(1) + "\t" + rs.getString(2) + "\t" + "\t" + rs.getString(3) + "\t" + rs.getString(4) + rs.getString(5) + "\t" + rs.getString(6) + "\t" + rs.getString(7) + "\n";
                System.out.println(ausgabe);
            }
           
            // Schliessen des Statements
            stmt.close();
           
        }
       
        catch (Exception ex)
        {
            System.out.println("Exception: " + ex.getMessage()); 
        }
 
        return ausgabe;
       
    }
```


Dann kannst Du die Connection übergeben:

```
public static void main (String[] args) {
        DatenbankKlasse eineVerbindung = new DatenbankKlasse();
        eineVerbindung.open();
       
        zeigeStudent einStudent = new zeigeStudent();
        einStudent.zeigStudent( eineVerbindung);

        eineVerbindung.close();
    }
```

(Habe den Code nur kopiert, nicht weiter auf Funktion getestet)


----------



## Guest (23. Jun 2006)

Hey super!! 

Das funzt  

Bin grad aufgestanden... sehr sehr guter Start in den Tag! 

Vielen Dank  

Ich übernehm das jetzt für meine anderen Klassen, dann dürfte es passen  

Schönen Tach noch!!


----------



## Guest (23. Jun 2006)

Ok, hoffentlich die letzt Frage, will euch net weiter Nerven mit meinem Zeugs.. 


das waren ja jetzt alles Klassen zum anzeigen... jetzt hab ich mal eine die soll einen Datensatz in der DB löschen.. bin mir net ganz sicher ob meine Umsetzung so stimmt: 


```
import java.sql.*;
import java.sql.PreparedStatement;

public class zuruecktretenKlausur
{
    
    
  public zuruecktretenKlausur() {
      
  }  
    
  public void treteZurueck(DatenbankKlasse dbk, String veranstaltungsnr) {
      
     try    {
         
        int rs;
        PreparedStatement stmt = null; 
      
            String aendern = ("DELETE FROM Klausur WHERE VeranstaltungsNr =?");
            stmt = dbk.getConnection().prepareStatement(aendern);
            stmt.setString(1, veranstaltungsnr);  
            
            stmt.executeUpdate();
            
            stmt.close();
            
     }
      catch (Exception ex)
        {
            System.out.println("Exception: " + ex.getMessage());  
        }
  }
  
}
```


Passt das so?? Weiss aber leider net wie ich da die main-methode gestalten muss? Gleich wie bei den anderen?? 


Danke im Voraus für eure Hilfe!!


----------



## merxleben (23. Jun 2006)

Hallo,

ich möchte nur mal kurz meinen Senf dazugeben. So wie ich das sehe legst du für jede neue Funktionalität eine neue Klasse an. Das widerspricht jeglichem OOP Gedanken. Für mich sieht das aus wie prozedurale Programmierung, die in ein Java Korsett gezwängt wird. Aber korrigiere mich, falls ich mich irre.



> Das heisst ich muss folgende Aufteilung machen:
> 
> 1) DatenbankKlasse ist lediglich fuer die Connection der Datenbank zuständig
> 2) In der (Fach)klasse StudentenAnzeigen soll lediglich das SQL Statement ausgeführt werden



Ich hoffe, dass waren nicht die konkreten Vorschläge deines Profs gewesen. Ansonsten würde ich an seinem Sachverstand zweifeln.

An einer anderen Stelle schriebst du, dass du eine klare Trennung in _Dialogschicht, Fachkonzept- und Datenbankschicht_ erreichen möchtest. Dazu würde ich empfehlen, dass du eine Klasse entwickelst, die nur für die Kommunikation mit der Datenbank zuständig ist, sprich Verbindung aufbauen und abbauen und auch erzeugen aller SQL Statements. Das hat den Vorteil, dass das Wissen über die konkret verwendete Datenbank an einer einzigen Stelle gebündelt ist (Information Hiding). Das könnte dann deine Datenbankschicht sein.

Was die Fachkonzeptschicht angeht. Dort müssten sich deine Anwendungsobjekte wie "Klausur", "Studenten" usw bewfinden. Über die Dialogschicht könnte ich jetzt nur spekulieren, daher lass ich das lieber.

Fazit des ganzen "meiner Meinung nach" ist. Identifiziere erst einmal alle Objekte in deinem Entwurf und packe die Methoden entsprechend zu den Objekten.

Ich hoffe das alles klingt jetzt nicht zu harsch. Ist auf jeden Fall nicht so gemeint.

Martin


----------



## Guest (23. Jun 2006)

Hi Martin, 

danke für deine Meinung. Leider bin ich noch sehr unerfahren in Sachen Programmierung und war mir von Anfang an nicht genau sicher ob das auch so sinn macht.. 

Vielleicht sollte ich nicht Klassen wie zeigeStudent oder aendereStudent nehmen, sondern eine Klasse Student wählen und Methoden wie zeige() und aendere() implementieren. Enspricht das eher dem OO Gedanken?? 

Eine Klasse sowohl für die DB Anbindung als auch für die SQL Statements.. hmm, das wäre natürlich besser, aber leider scheiterts am Wissen... Ich verraff dann immer wie ich die Assoziationen zwischen den Fachklassen und der einen DB Klasse aufbauen muss damit alles funktioniert... Weiss vielleicht jemand ein gutes Beispiel wo ich mir das anschauen kann? 

Ach, und Martin, deine Kritik war nicht harsch, sehr sachlich, hat mir weitergeholfen! 

Gruz,

Marko


----------



## merxleben (23. Jun 2006)

Hallo,

freut mich wenn ich helfen kann,



			
				Anonymous hat gesagt.:
			
		

> Vielleicht sollte ich nicht Klassen wie zeigeStudent oder aendereStudent nehmen, sondern eine Klasse Student wählen und Methoden wie zeige() und aendere() implementieren. Enspricht das eher dem OO Gedanken??



Das kommt der Sache auf jeden Fall näher. Beschäftige dich auf jeden Fall mal mit den Themen OOA und OOD. Die Programmierung ist dann bei einem guten Entwurf immer leichter.



			
				Anonymous hat gesagt.:
			
		

> Eine Klasse sowohl für die DB Anbindung als auch für die SQL Statements.. hmm, das wäre natürlich besser, aber leider scheiterts am Wissen... Ich verraff dann immer wie ich die Assoziationen zwischen den Fachklassen und der einen DB Klasse aufbauen muss damit alles funktioniert..



Dafür such mal unter dem Stichwort Singleton Pattern.

Falls noch was unklar ist, immer fragen

Martin


----------

