# Statement als Klassenvariable



## Wang (31. Mrz 2012)

Hallo,

ich zerbreche mir gerade darüber etwas den Kopf:
Man benötigt an vielen verschiedenen Stellen im Programm eine Verbindung zu einer bestimmten Datenbank. Um nicht ständig eine neue Verbindung herstellen zu müssen, instanziiert man am Anfang eine Klasse, die die Verbindung aufbaut und das Statement als Klassenvariable speichert, auf die dann immer über eine Klassenmethode zugegriffen wird, sodass die SQL-Anfrage gleich gestartet werden kann.

Ist das OK oder "moralisch bedenklich"? 

Thanks!

Gruß
Wang


----------



## SlaterB (31. Mrz 2012)

Connection irgendwo zu speichern ist kein Unding,
dafür gibts verschiedene Varianten, statt zentral kann es auch durch Hintergrundprozesse recht unauffällig überall hingeschoben werden (Injection),
pauschal nicht zu sagen, solange es geht ist es schon nicht schlecht

das Statement musst du nicht unbedingt speichern, neues Statement auf Connection ist nahezu gleichwertig,
wenn du über Methode getStatement() gehts ist sogar austauschbar, ob intern ein gespeichertes Statement zurückgegeben
oder die Connection um ein neues Statement gebeten wird,
close() im letzteren Fall nicht vergessen


----------



## maki (31. Mrz 2012)

Klassenvariable ist eine schlechte Idee.

Ein ConnectionPool löst das Problem elegant.


----------



## Wang (31. Mrz 2012)

SlaterB hat gesagt.:


> statt zentral kann es auch durch Hintergrundprozesse recht unauffällig überall hingeschoben werden (Injection)



Wie genau meinst Du das (kann mir gerade nichts darunter vorstellen)?



maki hat gesagt.:


> Klassenvariable ist eine schlechte Idee.
> 
> Ein ConnectionPool löst das Problem elegant.



Ich habe mich mit der Thematik jetzt mal im Buch "Java als erste Programmiersprache" schlau gemacht. Dort heißt es: 





> Connection Pooling ist vor allem für den Einsatz auf Applikations-Servern vorgesehen.



Ist Connection Pooling in meinem Fall mit der einfachen Desktop-Anwendung nicht etwas "mit Kanonen auf Spatzen schießen"? 

Davon mal abgesehen müsste ich doch wieder z.B. über eine Klassenmethode auf das zentrale Objekt zugreifen, das den Verbindungspool darstellt...?


----------



## SlaterB (1. Apr 2012)

das angerissene Gesamtkonzept ist
Dependency injection - Wikipedia, the free encyclopedia

wie alles kann man das natürlich vereinfachen, 
wenn es x Objekte gibt die die Connection brauchen, dann gibt es <= x Stellen wo diese erzeugt werden,
an diesen Stellen könnten sie im Konstruktor oder noch unauffälliger in Hintergrund-init-Methoden die benötigten Standard-Daten übergeben bekommen -> schon sind sie da, nix weltbewegendes

für eine einfache Applikation ohne Threads reicht eine Connection, das denke ich auch


----------



## tfa (1. Apr 2012)

> für eine einfache Applikation ohne Threads reicht eine Connection, das denke ich auch


Ich finde, auch in einer 2-Schicht-Anwendung ist ein Connection-Pool sehr hilfreich. Er kümmert sich um ein Reconnect bei Timeouts oder sonstigen Verbindungsabbrüchen, Connections werden automatisch geschlossen, wenn man sie nicht mehr braucht - das spart Ressourcen, usw. 
Das möchte man nicht selber programmieren, wenn man nicht muss.


----------



## Wang (1. Apr 2012)

Ich verwende diesen Treiber (MS Access wird *LEIDER* vom Lehrstuhl vorgegeben, entsprechend mies ist die Treiberauswahl):

StelsMDB (MS Access JDBC Driver) Documentation

Dieser Treiber beinhaltet anscheinend auch eine 'Connection Pool Data Source class' und eine 'singletonConnection'. Beides ist komplettes Neuland für mich und es wäre sehr nett, wenn jemand auf meine beiden Fragen eingehen könnte:

1.) Was ist der Unterschied zwischen einem 'Connection Pool', einer 'Singleton Connection' und einer 'Dependency injection'?
2.) Wenn man den "singletonConnection"-Modus aktiviert hat, spielt es doch keine Rolle (mal abgesehen davon, dass es ganz schlechter Stil ist), wenn man an jeder Stelle im Programm, an der man eine Verbindung zur ein und derselben Datenbank benötigt, ständig ein 
	
	
	
	





```
Connection connection = DriverManager.getConnection(...)
```
 schreibt, da der Treiber mit aktivierter 'singletonConnection' ohnehin nur eine einzige Verbindung zu dieser Datenbank zulässt; oder sehe ich das falsch?

Danke für Eure Mühe!

Gruß
Wang


----------



## SlaterB (1. Apr 2012)

> Reconnect bei Timeouts oder sonstigen Verbindungsabbrüchen, 
noch nie irgendwo je gesehen, aber wenn es sein muss

> Connections werden automatisch geschlossen, wenn man sie nicht mehr braucht - das spart Ressourcen
wenn ewig gebraucht und die ganze Zeit eine Connection offen, dann ist die Sache einfach


----------



## schnitt_tt (29. Apr 2012)

@all ..

hallo, habe die gleiche Frage, die Anworten sind mir noch zu unkonkret.

also: Eine Desktop-Anwendung verwendet die DB (Derby) im embedded Modus. Um nicht jedesmal eine Verbindung aufbauen zu müßen besitzt die Anwendung eine Klasse Datenbank, die ua während der Laufzeit der Anwendung eine ständig Verbindung zur Datenbank hält ( Variable con ). Die Klasse soll auch als "Anlaufpunkt" für andere Objekte/Methoden dienen und die Zugriffe auf die DB "kapseln" -> spricht fungiert als "Utility-Objekt" (weniger Schreibaufwand etc)


```
public class Datenbank {

   String        driver  = "org.apache.derby.jdbc.EmbeddedDriver";
   Connection con    = null;
   Statement  stmt   = null;
   String        name  = null;

   public Datenbank( String databaseLocation)  {
       // Treiber laden
       //-------------------------------------
       try 
       {
           Class.forName( this.driver ).newInstance();
       } 
       catch (InstantiationException e)    { e.printStackTrace(); }
       catch (IllegalAccessException e)    { e.printStackTrace(); }
       catch ( ClassNotFoundException e) { e.printStackTrace(); }

       this.name = "jdbc:derby:" + SystemUtil.addRootDir( databaseLocation);
       try
       {
         con = DriverManager.getConnection( this.name );
         con.setAutoCommit( false );
       } 
       catch (SQLException e) { e.printStackTrace(); }
   }
```

Die Anwendung ermöglicht es eine Tabelle x gleichzeitigzu beschreiben und zu lesen .
Bsp: Tabelle x enthält Analyse-Daten -> ( pro Analyse ca 300.000 Datensätze). Damit der Anwender während die Analyse-Daten Erzeugung läuft (schreiben der Werte in die DB) weiter arbeiten kann.(auswerten der Daten etc).
Die Anwendung muß natürlich sicherstellen, das der Anwender lediglich die "fertigen" Daten auswerten kann .... so weit so gut.

Die Verbindung (Variable con) wird doch lediglich benötigt damit man überhaupt man der Datenbank etwas machen kann (insert / update) ????. Wohl der "Kommunikations-Kanal" zwischen Datenbank und Programm. Über diese Kanal teilt man der Datenbank mit was zu erledigen ist:

       a) ein simples Statement
       b) eine Transaktion (kapselt diverse Statements / Stichwort CRUD)

ich gehe mal davon aus, das wenn man eine Statement/Transaktion an die DB abschickt, das dann der Kommunikationsweg blockiert ist, sprich die Anwendung muß warten bis die Transaktion beendet ist. Das hätte dann zur Folge das man die SandUhr sieht, solange die DB am werkeln ist. bzw wenn mehre Threads die gleiche Verbindung verwenden, wäre dann wohl auch die Sanduhr sichtbar oder vielleicht sogar exceptions, da die Verbindung nicht doppelt genutz werden kann.

Das Ziel ist wohl, keine Exceptions / Sanduhr zu erzeugen, deswegen sollte man sich wohl mit Connections-Pools auch bei Desktop-Anwendungen auseinandersetzen ??? -> dh die obige Klasse hätte dann wohl ein Connection-Pool Objekt .


@all bitte kein Hinweis auf ORM`s etc .... dafür kann man einen anderen thread aufmachen... die Vereinfachen sicherlich vieles, aber Hintergrundwissen ist sicherlich nicht von Nachteil


----------



## SlaterB (29. Apr 2012)

was ist denn die Frage, wieder ob das so ok ist?
bisher hast du nur eine Klasse mit Connection als Attribut, das ist so ok, meiner Meinung nach,
wenig überraschend nach den vorherigen Postings 
hauptsächlich Nachfrage ob nicht noch eine andere Frage besteht/ es um ein genaueres Detail geht


> ich gehe mal davon aus, das wenn man eine Statement/Transaktion an die DB abschickt, das dann der Kommunikationsweg blockiert ist

stimmt, mag sein


----------



## schnitt_tt (29. Apr 2012)

> > ich gehe mal davon aus, das wenn man eine Statement/Transaktion an die DB abschickt, das dann der Kommunikationsweg blockiert ist
> 
> stimmt, mag sein



stimmt / mag sein = ????? was denn nu ? 




> Das Ziel ist wohl, keine Exceptions / Sanduhr zu erzeugen, deswegen sollte man sich wohl mit Connections-Pools auch bei Desktop-Anwendungen auseinandersetzen ???



-> da aus meiner Sicht, bei Verwendung von threads mit DB-zugriff, diese sich durch die eine Connection sperren, bzw eine Exception ausgelößt wird .... stimmt da meine Vermutung ?


----------



## SlaterB (30. Apr 2012)

'stimmt / mag sein' sagt doch beides das gleiche aus, von der Nuance abgesehen, dass ich es nicht mit Sicherheit sagen kann?

wobei ich noch konkretiersen kann, dass es sicherlich keine programmatische Blockierung ist, beliebige Threads können mit der Connection arbeiten, da wird nichts gesperrt, es gibt keine Exception,
fachlich sollte aber die Connection exklusiv sein, es ist deine Aufgabe bzw. die für einen ConnectionPool usw., dafür zu sorgen


----------



## ARadauer (30. Apr 2012)

Wang hat gesagt.:


> Ist Connection Pooling in meinem Fall mit der einfachen Desktop-Anwendung nicht etwas "mit Kanonen auf Spatzen schießen"?


Nein auf keinen Fall. Die Verbindung zur Datenbank aufbauen ist etwas sehr teures. Das kann schon sein, dass das bis zu einer Sekunde dauert, ich würde Verbindungen auf jeden Fall in einem Pool cachen....


----------



## SlaterB (30. Apr 2012)

> auf jeden Fall in einem Pool cachen.... 

und in einer einfachen Anwendung ohne konkurrierende Threads mit mehreren Verbindungen reicht doch wohl 
eine Connection in einer statischen Variable als 'Cache'?


----------



## ARadauer (30. Apr 2012)

SlaterB hat gesagt.:


> >eine Connection in einer statischen Variable als 'Cache'?


mhnn... du itererierst übers ResultSet und möchtest für jeden Datensatz nochwas nachladen/updaten/löschen... ok man könnte es auch über ein komplexeres query machen, aber wenn nicht hast du schon das problem, dass du eine zweite verbindung brauchst...


----------



## tfa (30. Apr 2012)

> eine Connection in einer statischen Variable als 'Cache'?


Ein Connection-Pool kann ein Reconnect auslösen, falls sich die DB-Verbindung wegen Timeout o.ä. geschlossen hat. Auch kann der Pool die Connection bei längerer Nichtbenutzung automatisch schließen und so Ressourcen sparen. Das möchte man nicht von Hand programmieren.


----------



## SlaterB (30. Apr 2012)

> schon das problem, dass du eine zweite verbindung brauchst... 

eine Connection kann mehrere Statements haben, das funktioniert, nur mit nebenläufigen Transaktionen, eben Threads, wird es eine Stufe höher

das Sparen bei Schließen habe ich ja schon früher angesprochen, 
in einem einfachen Programm kommt es nie zu Timeouts, nie sind Ressourcen etwas worüber man nachdenkt,
eine Connection auf und fertig, das ist die einfachste Variante die normalerweise für alles (einfache) funktioniert,


----------



## tfa (30. Apr 2012)

> in einem einfachen Programm kommt es nie zu Timeouts


Aha, das wusste ich noch nicht. 



> eine Connection auf und fertig, das ist die einfachste Variante die normalerweise für alles (einfache) funktioniert


Ich finde ein Programm mit Connection-Pool einfacher als eins ohne. Es sei denn _einfach_ heißt _so_ einfach, dass es nicht immer funktionieren muss.


----------



## SlaterB (1. Mai 2012)

was passiert bei einem Timeout mit offenen Transaktionen?
wie werden mehrstufige Verarbeitungschritte mit Exception korrekt abgebrochen und neu gestartet?
nur auf ConnectionPool zu verweisen löst überhaupt keine Probleme

einen so schwerwiegender Fehler wie ein Problem mit der Datenbank kann in einem einfachen Programm nicht sinnvoll behandelt werden, 
jedenfalls (in der Regel) nicht von jemanden der überlegt ob eine Connection in einer statischen Variable abgelegt wird,
aus und neu an

75% aller einfachen Programme laufen sowieso nicht mehr als paar sec, und vom Rest sind 24% Dummy-GUI-Programme, die auch nicht viel mehr leisten,
die ganze Diskussion ist für mich surreal,
wenn man die entsprechenden Anforderungen hat, Probleme mit mehreren Threads sieht usw., landet man ganz automatisch bei den richtigen Strukturen,


----------



## cmrudolph (1. Mai 2012)

SlaterB hat gesagt.:


> eine Connection kann mehrere Statements haben, das funktioniert, nur mit nebenläufigen Transaktionen, eben Threads, wird es eine Stufe höher



Es muss nicht nebenläufig sein um mehrere Verbindungen zu benötigen.
Gesetzt den Fall, dass man zwei Tabellen hat. Die erste enthält Referenzen auf die zweite. Aus der ersten holt man sich die Referenzen, die eine bestimmte Bedingung erfüllen. Um das Beispiel realistischer zu machen, stehen in der ersten Tabelle noch viele andere Daten und die Ergebnismenge ist sehr sehr groß. Danach möchte man die Daten aus der zweiten Tabelle holen, die zu den gerade verarbeiteten gehören. Ich setzte mal voraus, dass ein simpler JOIN nicht funktioniert, weil das Kreuzprodukt zu groß wäre und die Laufzeit daher in den Keller ginge.
Um mit dem verfügbaren Speicher jetzt hinzukommen, verarbeitet man dann die Daten aus der ersten Tabelle sequentiell und holt sie erst von der Datenbank, wenn man sie benötigt. Zwischendurch benötigt man die zweite Verbindung, um die weiteren Daten zu verarbeiten.

Das ist kein so konstruiertes Beispiel wie es erscheinen mag - in der Praxis sind mir derartige Fälle schon untergekommen.


----------



## schnitt_tt (1. Mai 2012)

@SlaterB
für Einsteiger / Umsteiger ist das sicherlich *nicht* surreal ! (Wobei einsteiger sicherlich erstmalig die Finger von Threads lassen *g). 

Als Umsteiger wäre es ganz gut wenn man bei grundlegenen Dingen aufs richtige Pferd gesetzt wird, was durch diverse Foren manchmal echt schwer wird, bzw man selbst nicht abschätzen kann welchen TIP man folgt. (Komplexität,Halbwissen etc). 


zurück zum Topic:
Nach stöbern in der DB-Derby Doku bin ich auf das folgende gestossen (Das scheint sich auf die JDBC allgemein zu beziehen


> Pitfalls of sharing a connection among threads
> 
> Here is a review of the potential pitfalls of sharing a single Connection among multiple threads.
> 
> ...




daraus schlussfolgere ich: für Desktop-Anwendungen die Threads nutzen um "flüssigeres" Arbeiten bereitzustellen, fällt eine einzelne Connection flach, dh 1-n "Klassenvariablen oder Connection-Pool (CP).


Connection-Pool: es fehlt mir immer noch ein Grund diese "Fremd-Bibliothek" einzusetzen. Beim suchen im Netz fand ich nichts das für Embedded+CP sprach. Desweitren schreckt mich ab: die x-te LIB die den Standard verbesserte und alles was mit Fremd-Libs zusammenhängt (Stichwort: JODA bzw DATE/TIME, Lizenz geraffel etc).

thx


----------



## tfa (1. Mai 2012)

> 75% aller einfachen Programme laufen sowieso nicht mehr als paar sec, und vom Rest sind 24% Dummy-GUI-Programme, die auch nicht viel mehr leisten,
> die ganze Diskussion ist für mich surreal,


Das wusst ich auch noch nicht. Hast du eine Quelle für diese Zahlen oder stammen sie aus eigener Forschungsarbeit?
Surreal ist allerdings, mit derartigen _Argumenten_ gegen eine tausendfach bewährte best practice anzugehen.


----------



## SlaterB (1. Mai 2012)

cmrudolph hat gesagt.:


> Es muss nicht nebenläufig sein um mehrere Verbindungen zu benötigen.
> Gesetzt den Fall, dass man zwei Tabellen hat.[..]
> 
> Das ist kein so konstruiertes Beispiel wie es erscheinen mag - in der Praxis sind mir derartige Fälle schon untergekommen.


inwiefern widerspricht das dem gerade von dir zitierten Satz 'eine Connection kann mehrere Statements haben'?
natürlich braucht man mehrere offene Query gleichzeitig und genau das leisten mehrere Statements auf eine Connection


----------



## SlaterB (1. Mai 2012)

@tfa
jedes einzelne Anfänger-Thema zu JDBC, was man hier im Forum findet, wahllos in 2 sec das erste herausgegriffe
http://www.java-forum.org/datenbankprogrammierung/135209-jdbc-datenbank-funktioniert.html
verwendet eine einzelne Connection, insofern durchaus Forschungsarbeit wie du das so herablassend formulierst

zeig mal ein Thema hier im Forum mit ConnectionPool bei JDBC, 
Hibernate und JPA sind sowieso viele Stufen höher, da wäre Vorgehen gegen das Framework eher schwierig,
gibt es für JDBC überhaupt einen Pool-Standard?
auch bei google auf die Schnelle nichts gesehen

Connection Pooling
mit OracleConnectionPoolDataSource sieht ja sehr exotisch aus ("JNDI-Lookup"..)

im ersten Link zu JDBC-Tutorial 
Lesson: JDBC Basics (The Java™ Tutorials > JDBC(TM) Database Access)
taucht PooledDataSource unter
Connecting with DataSource Objects (The Java™ Tutorials > JDBC(TM) Database Access > JDBC Basics)
auf, auch wieder mit JNDI, was dann wohl der tausendfache Standard ist, um im gleichen Ton zu antworten


----------



## cmrudolph (1. Mai 2012)

SlaterB hat gesagt.:


> inwiefern widerspricht das dem gerade von dir zitierten Satz 'eine Connection kann mehrere Statements haben'?


Primär bezog ich mich auf den zweiten Teil des Zitates. Nämlich dass mehrere Verbindungen erst bei mehreren Threads notwendig seien.



SlaterB hat gesagt.:


> natürlich braucht man mehrere offene Query gleichzeitig und genau das leisten mehrere Statements auf eine Connection



Das dürfte aber vom DBMS abhängen. MySQL kann das nämlich nicht. Wenn man das versucht, dann bekommt man eine lapidare Fehlermeldung, dass die Synchronisation verloren ist.

Beleg hierzu:
Auszug aus der Dokumentation der aktuellen MySQL Version. Das Ergebnis einer Query muss demnach erst vollständig abgerufen werden oder das Ergebnis verworfen werden. In dem von mir aufgezeigten Beispiel kann man das Ergebnis aber nicht vorher vollständig in den Speicher laden und verwerfen möchte man es sicherlich auch nicht. Um in diesem Fall mit zwei Abfragen im Wechsel zu arbeiten, muss man zwei Verbindungen aufbauen.


----------



## SlaterB (1. Mai 2012)

@cmrudolph
nun, wenn das der Fall ist, wäre das ein Punkt, in der Tat, 
habe hier zu Java noch nie ein Thema gesehen wo jemand für sequentielle Verarbeitung als Lösung zwei Connections brauchte,

auch für höhere Frameworks, etwa Hibernate getSession() eine gewisse interne Herausforderung, könnte ich mir vorstellen,
klappen Transaktion über mehrere Connections usw?

edit:
Suche '"Commands out of sync" jdbc'
liefert als ersten Link 
Search Results Commands+out+of+sync%3B+you+can%27t+run+this+command+now - MySQL Performance Blog
mit Inhalt 'Sorry, no posts matched your criteria.'

recht weit unten als Suchergebnis
openoffice - dba dev - XOutParameters
mit fraglichen Java-Zusammenhang und auch sonst sehr wenig,
sicher dass das je in JDBC beobachet wurde?


----------



## cmrudolph (1. Mai 2012)

SlaterB hat gesagt.:


> sicher dass das je in JDBC beobachet wurde?



Nein, denn man kann diese Fehlermeldung "umgehen", indem man immer mysql_store_result verwendet. Falls JDBC das intern so macht, tritt diese Fehlermeldung nie auf. Stattdessen würde man in meinem Beispiel einen Speicherfehler bekommen, weil die Ergebnismenge zu groß ist.

Ich werde mal googlen, wie JDBC das handhabt.

[EDIT]





			
				Connector/J Dokumentation hat gesagt.:
			
		

> By default, ResultSets are completely retrieved and stored in memory. In most cases this is the most efficient way to operate, and due to the design of the MySQL network protocol is easier to implement. If you are working with ResultSets that have a large number of rows or large values, and cannot allocate heap space in your JVM for the memory required, you can tell the driver to stream the results back one row at a time.
> [...]
> There are some caveats with this approach. You must read all of the rows in the result set (or close it) before you can issue any other queries on the connection, or an exception will be thrown.


Link: MySQL :: MySQL 5.6 Reference Manual :: 21.3.5.2 JDBC API Implementation Notes

Es ist genau wie ich es vermutet habe: per default wird die gesamte Ergebnismenge abgerufen. Wenn man aufgrund der Ergebnismengengröße die Daten zeilenweise abholt, sind keine parallelen Queries mehr möglich (siehe zweiter Teil des Zitates).[/EDIT]


----------



## cmrudolph (1. Mai 2012)

SlaterB hat gesagt.:


> auch für höhere Frameworks, etwa Hibernate getSession() eine gewisse interne Herausforderung, könnte ich mir vorstellen,
> klappen Transaktion über mehrere Connections usw?



Nein, Transaktionen über mehrere Connections gibt SQL nicht her. Transaktionen sind zwar primär beim Schreiben von Daten relevant, wenn die Daten aber von einem gelesenen Datensatz abhängen, dürfte es Probleme mit der Transaktion geben. In diesem Fall könnte ich mir vorstellen, dass Hibernate und andere Frameworks Mechanismen wie Optimistic Offline Lock oder Pessimistic Offline Lock verwenden.
Damit werden diese Probleme umgangen.


----------

