# JDBC und Client/Server



## tinker (30. Apr 2007)

Guten Tag!
Ich beschäftige mich gerade mit Java-Sicherheit in Bezug auf Datenbanken. Also Sicherheitsmechanismen die Java bietet die für Datenbankzugriffe interessant sind. Zum einen befasse ich mich mit PreparedStatements und StoredProcedures und zum anderen mit der Sicherheit von Netzwerk-Übertragungen. Also JSSE. 

Nur lief die Datenbank bei mir bisher immer am selben Rechner wie die Applikation die darauf zugreift. Meine Frage lautet nun, wie ein Client/Server zugriff auf eine Datenbank aussehen würde. Ich nehme mal an es wird eine Client- und eine Serveranwendung geben. Nur weiß ich nicht welche Funktionen welche Anwendung ausführt. Als einfache Anwendung könnte ich mir vorstellen, das der Server alle DB-spezifischen Dinge erledigt und der Client ihm einfach ein Statement zukommen lässt. Der Server greift anschließend auf die DB zu und liefert dem Client ein Java-Objekt oder das ResultSet.

Kann man das so lassen oder gibt es bessere Ansätze?

tia,
tinker


----------



## Guest (30. Apr 2007)

Client <--> Serverschnittstelle  |dicke Leitung mit SSL|  Facade <--> Bussiness Logik <--> DAO Schicht <--> Datenbank

JDBC hat auf dem Client nichts zu suchen. Auch nicht ResultSets etc. Diese sollten bereits in der DAO Schicht in 
entsprechende POJOs konvertiert werden.


----------



## tinker (30. Apr 2007)

OK, könntest du die einzelnen Schichten jetzt noch kurz erleutern? tia


----------



## Guest (30. Apr 2007)

1) Serverschnittstelle (Pattern: Client side proxy)

Kapselt den Zugriff auf den Server (stellt dessen Funktionen zur Verfügung) und 
übernimmt die Konvertierung von DTOs in VOs und umgekehrt.

2) Facade (Pattern: Facade)

Bietet öffentliche Funktionen des Servers an. 

3) Bussiness Logik (Pattern: Bussiness object)

Die serverseitige Logik deiner Anwendung, inklusive Plausibilitätsprüfung, Rechteprüfung etc.

4) DAO Schicht (Pattern: Data access object)

Zugriff auf die Datenbank, Mapping von JDBC nach DTO und umgekehrt


----------



## Guest (30. Apr 2007)

Noch etwas. Alles, was irgendwie nach JDBC aussieht, sollte die DAO Schicht nicht verlassen. Auch keine 
SQLExceptions ausserhalb der DAO Schicht. Vorher in eigene Exceptions konvertieren und ohne die 
SQLException als Cause werfen. Die SQLExceptions kannst du in der DAO-Schicht loggen.
Damit verbaust du dir nicht die Option, etwas anderes als reines JDBC zu verwenden (z.B. Toplink, Hibernate etc.)


----------



## tinker (30. Apr 2007)

OK, so würde es in der Praxis ausschauen. Da ich mich aber primär mit dem Thema Sicherheit beschäftige ist ein derartiger Aufbau zu Testzwecken womöglich nicht nötig. Ich will einfach, zur praktischen Veranschaulichung, in einem Programm die gesamten, zuvor theoretische behandelten, Sicherheitsmechanissmen einbauen. 

Also einfach eine Umgebung wo der Client mit dem Server über eine verschlüsselte Verbindung kommuniziert und der Server dann auf die Datenbank mithilfe von PreparedStatements und StoredProcedures zugreift. Und da hab ich mir halt gedacht, dass der Client einfach einen String mit dem Select-Statement oder Übergabeparametern (für den Fall, das StoredProcedures verwendet werden) an den Server schickt und der die Daten dann aus der Datenbank holt und dem Client, wiederum üder die verschlüsselte Verbindung, ein POJO schickt. 

Das ganze wird eine Fachbereichsarbeit für die Schule mit dem Thema "Java-Sicherheit in bezug auf Datenbanken" und was ich jetzt wissen will ist eben ob so ein Aufbau ansatzweise mit der Praxis zu vergleichen ist. Also ob der Client überhaupt ein Select-Statement an den Server schickt, ob es sich dabei dann um einen String handelt usw., oder ob es da etwas anderes gibt. Das ganze sollte eben nicht zu komplex werden, da sich die Arbeit ja um Sicherheit dreht. 

Ich hoffe man versteht mein Anliegen

mfg


----------



## Guest (30. Apr 2007)

tinker hat gesagt.:
			
		

> ...was ich jetzt wissen will ist eben ob so ein Aufbau ansatzweise mit der Praxis zu vergleichen ist. Also ob der Client überhaupt ein Select-Statement an den Server schickt, ob es sich dabei dann um einen String handelt usw., oder ob es da etwas anderes gibt. Das ganze sollte eben nicht zu komplex werden, da sich die Arbeit ja um Sicherheit dreht.


Auf keinen Fall. Der Client hat nichts auf der Datenbank zu suchen.

Wenn du paar Beispiele zu JSSE suchst, schau dir die hier an: http://java.sun.com/j2se/1.4.2/docs/guide/security/jsse/samples/


----------



## tinker (30. Apr 2007)

Mit JSSE kenn ich mich eh schon aus. Nur brauch ich jetzt halt noch ein praktisches Beispiel wie ich das jetzt mit einem Datenbankzugriff verbinde. 



			
				Anonymous hat gesagt.:
			
		

> Auf keinen Fall. Der Client hat nichts auf der Datenbank zu suchen.


OK, nur wie sagt der Client dem Server (oder halt der Schicht die für den DB-Zugriff zuständig ist) dann was er braucht?  Was schickt er wenn er was aus der DB haben will, was schickt er wenn er was einfügen will, was wenn er was löschen will? 

Wie gesagt, bisher hat der Zugriff bei mir immer so ausgeschaut, dass ich an 
	
	
	
	





```
DriverManager.getConnection()
```
als url localhost übergeben hab. Als keine Spur von Client/Server Betrieb...


----------



## Guest (30. Apr 2007)

Du stellst für jede Operation eine ensprechende Funktion serverseitig zur Verfügung.
z.B.
	
	
	
	





```
interface Adressbuch
{
   /**
   * Liest alle Personen des Adressbuchs. 
   *
   * @throws AdressbuchException Fehler beim Lesen.
   */
   List<Person> readAll() throws AdressbuchException;

   /**
   * Liest eine Person anhand der gegebenen Id. 
   *
   * @param personId Id der zu lesenden Person
   * @throws AdressbuchException Fehler beim Lesen
   */
   Person read(Long personId) throws AdressbuchException;

   /**
   * Speichert die gegebene Person. 
   * Ist die gegebene Person nicht im Adressbuch enthalten, wird ein neuer Datensatz angelegt.
   *
   * @param person Zu speichernde Person
   * @return Die gespeicherte Person.
   * @throws AdressbuchException Fehler beim Speichern
   */
   Person save(Person person) throws AdressbuchException;

   /**
   * Löscht die Person mit der gegebenen Id. 
   *
   * @param personId Id der zu löschenden Person
   * @throws AdressbuchException Fehler beim Löschen
   */
   void delete(Long personId) throws AdressbuchException;
}
```


----------



## tinker (30. Apr 2007)

OK, dann hab ich nen Server der solche Funktionen zur Verfügung stellt. Der Client schickt ihm die Daten (Objekt, ID, ...) über eine sichere Verbindung und der Server gleift dann mit PreparedStatements oder Stored Procedures auf die Datenbank zu. Somit wäre dann alles in einem Beispiel. Right?


----------



## Guest (30. Apr 2007)

Right. 

Das hat auch den Vorteil, dass du den Client auch ohne Server entwickeln kannst, wenn du für Testzwecke 
einfach nur eine Implementierung der Schnittstelle schreibst, die paar Dummy-Objekte liefert.
z.B.:

```
class DummyAdressbuch implements Adressbuch
{
   private List<Person> personList;

   /**
   * Konstruktor. Initialisiert das Dummy-Adressbuch
   */
   public DummyAdressbuch()
   {
      personList = new ArrayList<Person>();
      personList.add(new Person(1, "Bart", "Simpson", ...));
      personList.add(new Person(2, "Homer", "Simpson", ...));
      personList.add(new Person(3, "Lisa", "Simpson", ...));
      ...
   }

   /**
   * Liest alle Personen des Adressbuchs.
   *
   * @throws AdressbuchException Fehler beim Lesen.
   */
   public List<Person> readAll() throws AdressbuchException
   {
      // Kopie, um keine Referenzen an Client zu übergeben
      List<Person> list = new ArrayList<Person>(personList.size());
      for(Person p : personList)
      {
         list.add(new Person(p));
      }
      return list;
   }

   /**
   * Liest eine Person anhand der gegebenen Id.
   *
   * @param personId Id der zu lesenden Person
   * @throws AdressbuchException Fehler beim Lesen
   */
   public Person read(Long personId) throws AdressbuchException
   {
      assert personId != null : "personId must not be null";
      Person person = null;
      for(Person p : personList)
      {
         if(p.getId().equals(personId))
         {
            person = new Person(p); // Kopie, um keine Referenz an Client zu übergeben
            break;
         }
      }
      // Keine Person mit gegebener Id vorhanden, dann Ärger machen
      if(person == null)
      {
         throw new AdressbuchException("Gibesnich");
      }
      return person;
   }

   ... usw.
}
```


----------



## tinker (30. Apr 2007)

Sehr schön, danke!


----------



## Guest (30. Apr 2007)

Ich habe da mal ein Beispiel geschrieben, wie so eine DAO Klasse aussehen könnte.
Siehe (BookDB) in http://www.java-forum.org/de/viewtopic.php?t=45823 
DBUtil für die Setter und Getter in ResultSet http://www.java-forum.org/de/viewtopic.php?t=43093

Den ganzen aufwand kann man sich aber sparen, wenn man einen vernünftigen OR-Mapper 
verwendet. Mit JPA (Java Persistence API) sowieso.


----------

