# Zugriff auf die DatenBank



## PollerJava (28. Sep 2007)

Hallo nochmal,

in meinem Programm lese ich alle 500ms (damit ich mein Programm stresse) aus einer DatenBank aus,
Der Benutzer kann parallel eine Aktion starten, in der etwas in die DatenBank geschrieben wird,


```
private Connection con;    // für das Lesen alle 500ms (nicht static) wird geöffnet und wieder geschlossen

protected static Connection con1;   // für Benutzerinteraktionen, bleibt bestehen
```

wenn der Benutzer jetzt etwas in die DatenBank schreiben will, dann kommt es darauf an, wann das ist.
Passiert dies zwischen den 500ms dann funktionierts, ansonsten bekomme ich die Fehlermeldung Reset is closed,

Meine Frage wäre jetzt, wie man das machen kann, das alle 500ms etwas aus der DB gelesen wird und dass ich auch in die DB etwas schreiben kann, wie macht man das normal (lesen stoppen und schreiben und dann wieder lesen???)


lg


----------



## tuxedo (28. Sep 2007)

Um alle 500ms zu lesen musst du doch nciht jedesmal die Verbindung komplett kappen, oder? Versteh den Hintergrund nicht.

Das was du suchst ist so eine Art Pool der die Lese-/Schreibaktionen verwaltet ...


- Alex


----------



## Wuschel87 (28. Sep 2007)

mach es über threads(wirst ja warscheinlich ehs chon tun), und wenn der knopf zum schreibeng edrückt wird stoppst den thread mit dem lesebefehl, dann den schreibbefehl ausführen und thread wieder starten  sollte klappen

(vorher vielleicht noch die connection schließen und wiede röffnen )

lg Wuschel


----------



## tuxedo (28. Sep 2007)

Ständig die Connection neu aufzubauen ist doch nicht performant?!

Wenn's drum geht zu verhindern dass gleichzeitig gelesen oder geschrieben wird ist ein Pool/Queue doch besser:

Eine Klasse die Lese und Schreibvorgänge entgegen nimmt und diese in einen Puffer schreibt. Ein Thread in dieser Klasse arbeitet dann dan Puffer Stück für stück ab. Ist halt nur dumm wenn man da jeweils noch das Ergebnis der Abfrage haben will... Dann ist der Puffer eher blöd. Dennoch wäre die Klasse mit den 2 Methoden für lesen und schreiben nicht verkehrt. Man sollte dann halt nur diese 2 Methoden synchronized machen damit sie nicht gleichzeitig aufgerufen werden können.

- Alex


----------



## PollerJava (28. Sep 2007)

Naja, irgendwer hat mal in diesem Forum geschrieben, nach dem Öffnen der Verbindung:


```
public Connection getConnection()
        {
        try {
            con = DriverManager.getConnection("jdbc:firebirdsql:localhost:c:\\...", username, passwort);
            }
        catch (Exception e)
            {   
            System.out.println();
            }
        return con;
        }
```

sollte die Verbindung wieder geschlossen werden:




```
public void closeConnection()
        {
        try {
            con.close();
            }
        catch (Exception e)
            {
            System.out.println();
            }
        }
```

Kann man das pauschal irgendwie sagen, wie lange das schließen und das öffnen der Verbindung benötigt??

Wie würde das mit dem Pool funktionieren, gibts da ein Beispiel dafür?

lg


----------



## tuxedo (28. Sep 2007)

Was du schließen sollst ist das ResultSet, sobald du die für dich wichtigen Daten extrahiert hast um damit weiter zu arbeiten.

Aber jetzt stell dir ein Programm vor das viele Anfragen an die DB macht... Und für jede Anfrage baust du die verbindung auf, führst sie aus und beendest die Verbindung wieder... 

Ich hab deinen ersten Post jetzt nochmal durchgelesen und ihn diesmal vermutlich verstanden:

Wenn du die Verbindung aufrecht erhälst, hast du das Problem nicht mehr mit dem "wann erfolgt der Zugriff". Du scheinst schlicht und einfach "ResultSet schließen" mit "Connection schließen" verwechselt zu haben. 

Vergiss für's erste das mit dem Pool wieder... 

btw:
statt

```
catch (Exception e){
System.out.println();
}
```

wirst du hoffentlich besser sowas 


```
catch (Exception e){
e.printStackTrace();
}
```

machen.. Oder noch besser die Exception ordentlich abfangen und darauf reagieren.

- Alex


----------



## maki (28. Sep 2007)

Falls du dich für einen JDBC Connection Pool interessierst, kannst du dir ja mal den von den jakarta-commons ansehen:

http://commons.apache.org/dbcp/

http://svn.apache.org/viewvc/common...riverExample.java?revision=560660&view=markup


----------



## PollerJava (28. Sep 2007)

Und wie soll ich das mit meinen 2 Verbindungen machen (con und con1), Das stört mich ziemlich,
Ist es OK, eine Verbindung (con) zu haben und über diese alles durchzuführen und soll diese static sein oder eine Objektvariable?

lg und vielen Dank


----------



## tuxedo (28. Sep 2007)

Ähm, du stehst gerade etwas neben dir:

Im Normalfall hast du deine einzige Connection zur DB die am besten irgendwo am Programmbeginn geöffnet wird, und vor dem Programmbeenden geschlossen wird. Dazwischen gehen alle Anfragen an die DB über diese eine Connection. Diese Static zu machen finde ich keine gute Idee. Du solltest dein Programm eher in verschiedene Schichten aufbauen:

GUI-Schicht
Logik-Schicht
DB-Schicht 

Wenn jetzt irgendwo in der GUI über einen Button eine Abfrage ausgelöst wird geht das Event runter in die Logikschicht. Da wird geschaut: Was will der User damit eigtl? Und die Logikschicht macht dann über die DB-Schicht die Abfrage. Die Schichten solltest du miteinander via Objektreferenzen etc. verlinken. D.h. die GUI-Schicht hat eine Referenz zur Logikschicht. Due GUI kann hier in ihren "actionPerformed"-Methoden, Methoden in der Logik aufrufen. Die Logikschicht hat eine Referenz zur DB-Schicht. Die von der GUI aufgerufenen Logik-Methoden rufen dann wieder DB-Methoden in der DB-Schicht auf.

Wenn du das noch schön über Interfaces regelst kannst du die Schichten beliebig austauschen ;-) Beispielsweise ne Andere GUI drauf setzen oder die DB-Schicht durch eine Datei-basierte-DB-Schicht ersetzen... 

- Alex


----------



## PollerJava (28. Sep 2007)

AJ das MVC (D) - Muster hab ich implementiert nur der Datenbankzugriff hat nicht ordentlich funktioniert da ich, wie ich nur eine con gehabt habe, immer ein ResultSet is closed bekommen habe, 
Mit 2 hats dann funktioniert -> und das irgendwie möchte ich eben jetzt auflösen,

vielen dank für die Hilfe,

lg


----------



## tuxedo (28. Sep 2007)

Wo liegt denn da das Problem?

- Alex


----------



## PollerJava (1. Okt 2007)

alex0801 hat gesagt.:
			
		

> Du scheinst schlicht und einfach "ResultSet schließen" mit "Connection schließen" verwechselt zu haben.



http://www.java-forum.org/de/viewtopic.php?p=323907 // vorletzter Beitrag,


Hier hab ich das mit dem Schließen der Verbindung her (Zitat von Gast: "Eigentlich gehört die Verbindung auch geschlossen")

Werds  aber jetzt umschreiben, sodass ich nur das ResultSet schließe,

lg und danke für die Tipps


----------



## tuxedo (1. Okt 2007)

Also 
ich muss dem Gast in verlinkten Beitrag ein wenig widersprechen:

Wenn ich Prepared Statements verwende,  und immer mal wieder die gleiche Art von Anfrage mache, dann ist es blödsinn die Verbindung zu beenden. Grund: Prepared Statements haben eine Lebensdauer, begrenzt auf die aktuelle Verbindung. Schließe ich die Verbindung hab ich den Vorteil der P.S., dass das Statement in der DB schon "vorgefertigt" ist und demnach etwas schneller ausgeführt werden kann, nicht mehr. 

Wenn du natürlich genau weißt, dass du die nächste Zeit definitiv keine DB-Anfrage in deinem Programm machst (also beispielsweise ausschließlich bei Programmstarte), dann machts auch keinen Sinn die Verbindung offen zu halten. 

Ach ja, noch was: Je nach DB-Config wird der Db-Server die Verbindung nach einer gewissen Zeit Inaktivität kappen. D.h. du solltest darauf vorbereitet sein und sowas ggf. per Exception abfangen und die Verbindung neu aufbauen.

- Alex


----------



## PollerJava (1. Okt 2007)

Hallo nochmal,

ich hab jetzt folgendes gemacht (alles ohne try-catch):


```
public Connection  createDBConnection(String pfad, String username, String passwort)
        {   
        return con = DriverManager.getConnection(pfad, username, passwort);    
        }

public Connection getDBConnection()
        {       
        return con;
        }

 public void closeDBResultSet()
        {      
        rs.close();         
        }
```



```
Klasse DBDriver:

// diese Methode liest aus der DatenBank aus, wenn der Benutzer einen Button drückt
public synchronized void findFile(String zeitstempel, Timestamp tsAktStart, Timestamp tsAktEnd, String dBName)              
        {                           
        stmt = getDBConnection().prepareStatement(String.format("SELECT zeitstempel, wert FROM %s WHERE zeitstempel BETWEEN ? AND ?", dBName));
        stmt.setTimestamp(1, tsAktStart);
        stmt.setTimestamp(2, tsAktEnd);
        rs = stmt.executeQuery();  
        while(rs.next())                        
             dBWerte.put(rs.getString("zeitstempel"), rs.getFloat("wert"));                          
        stmt.close();
        closeDBResultSet();
        aktuell = null;
        calendar = null;
        tsAktStart = null;
        tsAktEnd = null;
        }


// diese Methode schreibt z.B.: alle 2 Sekunden in die Datenbank
protected synchronized void fillTable(String tableName, Timestamp kommen, float wert, Timestamp gehen, Timestamp quit, String alarmNr, int var1, int var2)
       {
       PreparedStatement stmt = null;          
       stmt = getDBConnection().prepareStatement(String.format("INSERT INTO %s (zeitstempel, wert) VALUES ( ? , ?)", tableName));
       stmt.setTimestamp(1, kommen);
       stmt.setFloat(2, wert);
       stmt.executeUpdate();
       stmt.close();
       closeDBResultSet();  
       }
```

Ab und zu bekomme ich dann folgende Fehlermeldung und ich weiß nicht, wie ich das lösen kann.
Ich vermute mal, dass beide oberen Methode auf die DB zugreifen und die erste, die fertig ist, den ResultSet schließe und ich dann eben die fehlermeldung von unten bekomme:


```
Fehler in der Klasse DBDriver beim Auslesen aus der DB: org.firebirdsql.jdbc.FBSQLException: Result set is already closed.
org.firebirdsql.jdbc.FBSQLException: Result set is already closed.
        at org.firebirdsql.jdbc.FBStatementFetcher.checkClosed(FBStatementFetcher.java:232)
        at org.firebirdsql.jdbc.FBStatementFetcher.fetch(FBStatementFetcher.java:187)
        at org.firebirdsql.jdbc.FBStatementFetcher.next(FBStatementFetcher.java:137)
        at org.firebirdsql.jdbc.FBResultSet.next(FBResultSet.java:250)
        at datenbank.DBDriver.findFile(DBDriver.java:230)
        at component.CheckList.setShift(CheckList.java:113)
        at component.Trend.aktTrend(Trend.java:537)
        at component.TrendAkt.run(TrendAkt.java:26)
        at java.util.TimerThread.mainLoop(Timer.java:512)
        at java.util.TimerThread.run(Timer.java:462)
```


----------



## maki (1. Okt 2007)

> Ab und zu bekomme ich dann folgende Fehlermeldung und ich weiß nicht, wie ich das lösen kann.
> Ich vermute mal, dass beide oberen Methode auf die DB zugreifen und die erste, die fertig ist, den ResultSet schließe und ich dann eben die fehlermeldung von unten bekomme:


Hast du mehrere Threads am laufen?


----------



## tuxedo (1. Okt 2007)

;-) 

Wenn du ein Statement hast, das irgendwas in der Tabelle selektiert, dann solltest du das Resultset erst dann schließen, wenn du die abgefragten Daten aus dem RS rausgeholt hast.

Das ist das eine. Das andere ist:

Deine fillTable-Methode erzeugt gar kein offensichtliches Resultset, und dennoch schließt' du's. Schau dir doch mal den "return"-Wert von executeUpdate(); an ...

- Alex


----------



## maki (1. Okt 2007)

> Hast du mehrere Threads am laufen?


Meine Frage kann ich seber beantworten: Ja, du hast mehrere Threads am laufen.

Spätestens jetzt wäre es an der Zeit, eine vernünftige DB Zugriffsschicht zu implementieren, mit DAOs. 
Oder du nimmst einfach iBatis.


----------



## PollerJava (1. Okt 2007)

JA, die Methode 


```
protected synchronized void fillTable(String tableName, Timestamp kommen, float wert, Timestamp gehen, Timestamp quit, String alarmNr, int var1, int var2)
       {
       PreparedStatement stmt = null;         
       stmt = getDBConnection().prepareStatement(String.format("INSERT INTO %s (zeitstempel, wert) VALUES ( ? , ?)", tableName));
       stmt.setTimestamp(1, kommen);
       stmt.setFloat(2, wert);
       stmt.executeUpdate();
       stmt.close();
       closeDBResultSet(); 
       }
```

rufen 5 Threads auf:


```
for (int i = 0; i < 5; i++)
dBTimer.scheduleAtFixedRate(new DBWriter(..., ... usw));             
            
        
    
public void run()                                                           // Werte in die Datenbank schreiben
        {
        fillTable(tableName, kommen, wert, gehen, quit, alarmNr, var1, var2);
        }
```


----------



## PollerJava (1. Okt 2007)

alex0801 hat gesagt.:
			
		

> ;-)
> 
> Deine fillTable-Methode erzeugt gar kein offensichtliches Resultset, und dennoch schließt' du's. Schau dir doch mal den "return"-Wert von executeUpdate(); an ...
> 
> - Alex




Ja stimmt, danke (Rückgabe ist ein int)


----------



## maki (1. Okt 2007)

Nix für ungut, aber wenn du einen DB zugriff so implementierst... naja, Schwamm drüber.

Einfach neu und diesmal richtig machen 

http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

http://ibatis.apache.org/


----------



## PollerJava (1. Okt 2007)

naja, das ist das erste mal, dass ich von mehreren Seiten auf eine Datenbank zugreife und von DAOs hab noch nie etwas gehört obwohl ich das Java Handbuch und Java ist auch eine Insel und das Java Kompnedium gelesen habe (Vielleicht hab ichs auch überlesen, hab aber versucht, sehr genau zu lesen),

Gibts da irgendeinen Code, denn ich auch verstehe und den ich leicht implementieren kann, 

http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html  scheint ja ziemlich kompliziert zu sein,

Ich verwende die fireBird- Datenbank,

lg und vielen Dank


----------



## maki (1. Okt 2007)

> naja, das ist das erste mal, dass ich von mehreren Seiten auf eine Datenbank zugreife und von DAOs hab noch nie etwas gehört obwohl ich das Java Handbuch und Java ist auch eine Insel und das Java Kompnedium gelesen habe (Vielleicht hab ichs auch überlesen, hab aber versucht, sehr genau zu lesen),


DAOs istso was wie ein "best practice", gabs vor Java auch schon. 



> Gibts da irgendeinen Code, denn ich auch verstehe und den ich leicht implementieren kann,
> 
> http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html scheint ja ziemlich kompliziert zu sein,


iBatis hat das schon implementiert, dafür musst du iBatis lernen 
Du brauchst übrigens die SQL Maps nicht zu verwenden, kannst das DAO Framework auch unabhängig verwenden.

Kompliziert ist es nicht, eine AbstractFactory eben.

Oder diese Möglichkeiten: 

1. Du sorgst dafür, das der zugriff auf die Connection, das Resulset und das Statement synchronisiert sind.

2. Gib jedem Thread seine eigene Connection


----------



## tuxedo (1. Okt 2007)

Also ich fand iBatis ganz schick. Hatte in nur wenigen Minuten das Tutorial durch. Alles in allem: ziemlich coole Sache und ziemlich easy.

http://ibatis.apache.org/
Tutorial: http://ibatis.apache.org/docs/java/pdf/iBATIS-SqlMaps-2-Tutorial_en.pdf

- Alex


----------



## PollerJava (1. Okt 2007)

maki hat gesagt.:
			
		

> > Kompliziert ist es nicht, eine AbstractFactory eben.
> >
> > Oder diese Möglichkeiten:
> >
> ...


----------



## tuxedo (1. Okt 2007)

Kann mir im übrigen nicht vorstellen dass im Pflichtenheft steht "Es dürfen keine XML-Dateien benutzt werden" .. Nur für den Fall dass du das Turorial nur Oberflächlich angeschaut hast: In den XMLs steht nur, wie Teile der Datenbank auf ein Java-Objekt gemappt werden. Die XMLs selbst stellen keine Datenbank dar sondern nur eine Art Konfigurations-Datei.

Zu DAO: http://de.wikipedia.org/wiki/Data_Access_Object

Ich hab bis jetzt nicht allzuviele APIs in Bezug auf DAO in der Hand gehabt, aber alle die ich in der hand hatte haben eine Mapping-Beschreibung in Dateiform benutzt, und das Format in der Datei war nunmal XML.

Prinzipiell kannst du dir's ja selbst basteln wenn du _unter gar keinen Umständen_ XML Dateien für die Konfiguration benutzen darfst. Aber warum das Rad neu erfinden wenn wenn es schon Libs gibt die das machen (und halt leider gottes XML für's mapping verwenden).

- Alex


----------



## PollerJava (1. Okt 2007)

naja im Pflichtenheft steht, es ist im Projektordner eine Datei anzulegen in dem die Konfigurationsdatei und die Passwort- Datei zu hinterlegen ist und das ist ziemlich streng gemeint aber ich werd mich da jetzt darüber hinwegsetzt und es so machen,

Ich hab jetzt nach Java- Code gesucht, bin aber noch auf nichts gestoßen,
Wieviel Aufwand ist das, von meinem Stand weg das DAO zu implementieren und kann ich meine momentane Implementierung im Großen und Ganzen so lassen oder muss ich viel ändern?

lg


----------



## maki (1. Okt 2007)

> Also mit FactoryMethode und AbstarctFactory kenn ich mich halbwegs.


Das ist schon mal gut, eine DAOFactory ist nämlich nix anderes, wenn du nur eine DB hat könntest du auch gleich eine ConcreteFactory benutzen, ohne den Umweg über die AbstractFactory.



> Jedem Thread seine eigene Connection geben, möchte ich eher vermeiden da ich nicht nur 5 Threads haben kann sondern unbekannt viele oder auch wenige,
> Mir wird also nichts anderes übrig bleiben als mich in DAO zu stürzen, oder,


Du  musst keine DAOs einsetzen wenn sie dich verwirren.
Allerdings sehe ich keinen Grund, warum nicht jeder Thread seine eigene Connection haben sollte, lässt sich sehr elegant lösen mithilfe eines ConnectionPools (hatte ich hier schon gepostet).



> ch hab mir jetzt das Tutorial von iBatis durchgelesen kann dieses aber leider nicht verwenden, da keine XML- Datei (ausser für die des Kunden) angelegt werden sollen (Pflichtenheft),


Da hast du ein paar Dinge verwechselt:
1. Die XML Dateien gehören zu deinem Sourcecode, darin werden keine fachlichen Daten gespeichert, es handelt sich um Konfigurationsdaten und Quellcode (dein SQL steckt da drinnen).
2. Du brauchst keine SQL Maps, du brauchst das DAO Framework: http://ibatis.apache.org/docs/java/pdf/iBATIS-DAO-2_en.pdf
Ignorier einfach die SQLMaps, an ihrer Stelle führst du dann JDBC Aufrufe direkt aus, wenn dich die SQLMaps verwirren (sind aber wirklich besser  )



> Hab ich das richtig verstanden, dass ein DAO also ein Entwurfsmuster ist?


Ja 



> Kann ich das DAO auch in einer Java- Applikation verwenden (DAO ist ja für Enterprise) bzw. wie viel Adaptionsaufwand ist das und gibt es Code für eine DAO in einer Java- Applikation,


DAO ist nicht nur für Enterprise und schon gar nicht nur für Java, es macht keinen Unterschied ob es eine Desktop Anwendung ist oder in einem JEE Umgebung läuft (in der JEE gibt's mehr Mölichkeiten der Konfiguration, das ist alles).

IMHO sollte jeder, der einen DB Zugriff implementiert sich zumindest mal mit DAOs auseinandersetzen.



Willst du eine schnelle Lösung, dann muss jede Methode, die einen DB Zugriff macht:
- nur lokale Variablen verwenden, keine Instanz-und schon gar keine Klassenvariablen!

- jedesmal eine neue(*) Connection holen, ein neues Statement erzeugen und dann natürlich ein neues Resultset benutzen

- alle Resourcen (Connection, Statement ResultSet) müssen nach ihrer Benutzung wieder geschlossen werden.

* Wenn du einen ConnectionPool verwendest, ist das keine Geschwindigkeitsverlust.


----------



## tuxedo (1. Okt 2007)

PollerJava hat gesagt.:
			
		

> naja im Pflichtenheft steht, es ist im Projektordner eine Datei anzulegen in dem die Konfigurationsdatei und die Passwort- Datei zu hinterlegen ist und das ist ziemlich streng gemeint aber ich werd mich da jetzt darüber hinwegsetzt und es so machen,



MIr scheint du hast nicht ganz verstanden was ein Pflichtenheft ausmacht. Im Pflichtenheft steht hauptsächlich drin was gemacht werden MUSS (deswegen auch "Pflicht"). D.h. du kannst nicht einfacg die Konfigurationsdatei weglassen. Solange aber keine Kundenanfoderung besagt "Das Projekt DARF NUR aus .CLASS-Files und der Konfigurationsdatei" bestehen, darfst nach Lust und Laune weitere Dateien hinzunehmen. Und wie maki ja schon geschrieben hat, gehören die XML-Files von iBatis mit zum Quelltext und sind i.d.R. nicht für den Benutzer gedacht.

- Alex


----------



## PollerJava (1. Okt 2007)

Vielen Dank für die Erklärungen!!!
Ich sehe momentan den Baum vor lauter ....

Ich werd mich mal in die DAOs einlesen, ich will sie auch verwenden und bin auch sehr interessiert in Entwurfsmuster (Hab das Buch von O'Reilly -> Entwurfsmuster gelesen und setze immer mehr ein wos Sinn macht, von DAO stand aber da nichts drinnen, is wahrscheinlich zu speziell o.ä)
aber der liebe Zeitdruck ist mom. ziemlich hoch aber was solls,

Dankeschön,

lg


----------



## maki (1. Okt 2007)

Der grösste Vorteil von DAOs ist, dass es die DB technologie kapselt , d.h. wenn du später andere DB arten verwendest (Hibernate, XML, etc. pp.) musst du deine fachlichen/GUI Klassen nicht mitanpassen, die Änderungen bleiben Transparent.
Dein JDBC und SQL Code ist nicht über die ganze Anwendung verteilt, sondern nur in der DAO Schicht 

Die SQL Maps sind auch super:
JDBC Code bläht die Sourcen wirklich auf(geschachtete try/catch Blöcke, statements zusammen bauen, werte konvertieren etc., resourcen freigeben ), da gibt es viele Möglichkeiten Fehler zu machen.
Aber zuerst kommen die DAOs


----------



## PollerJava (1. Okt 2007)

Ja aber wie fange ich an, ich habe mir iBatis-DAO-2_en.pdf durchgelesen und mir das BeispielProgramm JPetstore 5 demo application heruntergeladen, 
kann ich mit dem was anfangen bzw. kann ich das verwenden?

lg


----------



## maki (1. Okt 2007)

PollerJava,

das bringt alles nix wenn du nicht verstehst was du da machst.

Eine "out of the box" Lösung gibt es nur, wenn du dich reinliest.
Wenn du das gemacht hast, wirst du keine Grund mehr sehen, iBatis einzusetzen.

Wie gesagt, es geht auch ohne DAOs, um mich selbst zu zitieren:


> Willst du eine schnelle Lösung, dann muss jede Methode, die einen DB Zugriff macht:
> - nur lokale Variablen verwenden, keine Instanz-und schon gar keine Klassenvariablen!
> 
> - jedesmal eine neue(*) Connection holen, ein neues Statement erzeugen und dann natürlich ein neues Resultset benutzen
> ...


Das wäre für dich am einfachsten zu bewerkstelligen.

Wenn du es einfach haben wilst, dann ist das dein Weg.

Willst du es mit Mustern (DAO) lösen, ist iBatis dein Freund, oder du machst es komplett selber.


----------



## PollerJava (1. Okt 2007)

Nö, ich werds mit den DAOs machen, 
also einlesen, verstehen und dann meinen DAO- Code stricken wenn ich das richtig verstanden habe ???:L


----------



## tuxedo (1. Okt 2007)

Ich fand den Weg mit den XMLs sehr einfach und gut erklärt. Zudem hat man den Vorteil nicht den Compiler anwerfen zu müssen wenn sich was an der DB-Struktur ändert, weil man's einfach in der XML ändern kann. 

In das Thema "reingefunden" hab ich allein durch das Tutorial. 

- Alex


----------



## PollerJava (1. Okt 2007)

Spalte | Spalte | ...

ich habe mehrere Tabellen, die so aussehen -> String name | Float Wert
und eine Tabelle, die so aussieht -> Timestamp ts1 | Timestamp ts2 | Timestamp ts3 | String str1 | INT i1 | INT i2

für diese Tabellen lege ich mir mal eine XML- Datei an, welche diese Tabellen repräsentieren (wie im Tutorial beschrieben ),

Mein Problem ist, dass die Tabellen in der DB erst erstellt werden, wenn die Applikation das erste mal gestartet wird (ich weiß also nicht, wievielen Tabellen es sind -> wie viel ich in der XML- Datei anlegen muss)

ich verwende dann eben in meiner Klasse an den verschiedenen stellen (in meinen 2 Methoden, wo ich etwas in die DB schreiben will):


```
private static final SqlMaapClient sqlMap;
...

sqlMap.insert("insertWieInDerXMLSteht", Datensatz);
```

Ich frag mich jetzt, ob das mein Problem löst ("ResultSet ist closed"), da ich ja wieder von meinen 5 Threads auf die DB zugreife über die XML- Datei halt, oder?

Wäre sehr dankbar für Hilfe,

lg


----------



## tuxedo (1. Okt 2007)

Ich behaupte jetzt mal dass dein DB-Design schlecht ist wenn die Anzahl der Tabellen variabel ist und sich "ändern" kann. Am besten du erklärst mal genauer das wieso und warum.

Die Sache mit dem ResultSet:

Da wirst du keine Probleme haben da du mit einem Resultset nicht mehr direkt in Berührung kommst. Macht iBatis für dich.


----------



## PollerJava (1. Okt 2007)

Beim ersten mal starten der Applikation wird aus einer XML- Datei ausgelesen, wieviel Tabellen angelegt werden sollen,

Bestehen die Tabellen schon in der DB und die Appl wird gestartet, dann wird eben in der DB nachgesehen, ob die Tabellen schon bestehen oder nicht und dann eben angelegt oder auch nicht,

Das ist aber eh das geringste Problem,


> Da wirst du keine Probleme haben da du mit einem Resultset nicht mehr direkt in Berührung kommst. Macht iBatis für dich.



Also das hab ich dann nocht nicht durchschaut, wo macht den das IBatis? in der Config- XML- Datei?

vielen Dank für die Unterstützung, war ja schon vor der Verzweiflung!!


----------



## maki (1. Okt 2007)

Ähm, wenn du Tabellen abfragen willst, musst du die Tabellen schon kennen bevor dein Programm läuft, sonst wird das nix.

Ich nehme an, die möglichen Tabellen der XML Datei sind dir schon beim kompilieren bekannt?



> Also das hab ich dann nocht nicht durchschaut, wo macht den das IBatis? in der Config- XML- Datei?


Das läuft im SqlMap Framework ab, da brauchst du keine Details zu kennen, dafür hast du ja iBatis.
Einen Überblick solltest du dir aber auf jedenfall besorgen, des Verständnisses wegen.

Wichtig für dich ist nur der Rückgabewert deiner DAOs:
- Ein einzelnes Objekt (eines "deiner" Objekte, oder nur HashMaps  )
- Eine Liste von Objekten (Eine Liste diner Objekte, oder eine Liste von HashMaps)
- Einen numerischen wert für die ID des zuletzt eingefügten  Datensatzes (int, long, Integer, Long, etc. pp. ) bei identity feldern.

DAOs eignen sich übrigens hervoragend als Generische Typen, aber das ist was für Fortgeschrittene.


----------



## tuxedo (1. Okt 2007)

Hast du den Sinn und Zweck von iBatis überhaupt verstanden?

Sinn und zweck ist es JDBC und alles was mit SQL zu tun hat aus dem direkten Java-Code zu entfernen. D.h. wenn du das so machst wie in dem Tutorial brauchst du dich um nix mehr kümmern was DB-Verbindungen, Resultsets, Statements etc. angeht (naja, fast, die XML musst du halt erst anlegen).

Intern macht ibatis das in etwa so:

Es frägt laut deiner Angabe in der XML die DB ab und holt sich die Spalten. Parallel zur XML hat dir das Tutorial ja gezeigt wie das Transportobjekt "Person" angelegt wird. Wenn du jetzt eine Person aus der Db abfrägst wird die Ergebnistabelle zerlegt und die Werte in ein neu instantiiertes Personenobjekt eingetragen. DB-Verbindungsaufbau und die Sache mit dem Resultset macht iBatis für dich.

Beim einfügen in die DB gehts ähnlich:

Du hast ein Personen-Objekt welches alle Personendaten enthält. iBatis nimmt dieses Objekt, holt sich alle Daten aus dem Objekt und befüllt damit den SQL-String in deiner XML und führt diesen dann aus. Fertig. 
D.h. du arbeitest nur noch mit einfachen Objekten und hast den SQL-Teil weit weg vom Code. Und das tolle ist: Du kannst die DB komplett tauschen und auch eine andere Struktur der DB wählen. Einfach die XML anpassen und dein Programm läuft mit der anderen DB und der anderen Struktur (vorrausgesetz in der neuen DB und Struktur sind _irgendwo_ die Infos vorhanden um eine Person zusammenzubauen).

Die Sache mit dem ersten anlegen der Tabellen: Ja, das könntest du in eine eigene Methode auslagern, die direkt nach programmstart und noch vor iBatis das ganze prüft und ggf. die Tabellen erstellt. Danach ist dann aber iBatis dein Kontakt zur DB. D.h. die DB_Connection und die Sachen mit dem Resultset was du zum prüfen und erstellen der Tabellen brauchst bleibt alles in der einen Prüf- und Anleg-Methode und wird NUR DORT und NUR FÜR DIESEN ZWECK benutzt. 

- Alex


----------



## ms (1. Okt 2007)

Das Problem mit dem Anlegen wird wohl sein, dass zwar Tabellen dazukommen können aber die entsprechenden xml-Files und die Objekte natürlich nicht existieren.

ms


----------



## maki (1. Okt 2007)

> Das Problem mit dem Anlegen wird wohl sein, dass zwar Tabellen dazukommen können aber die entsprechenden xml-Files und die Objekte natürlich nicht existieren.


Ja, deswegen auch meine Frage, ob er die Tabellen schon beim komilieren kennt, die er abfragen will.

Wenn nicht, ist iBatis nutzos für ihn.


----------



## tuxedo (1. Okt 2007)

?? Aber ich weiß doch vorher mit welchen Tabellen und Daten ich es zu tun habe? Also kann ich ja auch vorher XMLs und Transportobjekte bauen.

Ich denke gemeint war sowas wie bei HSQLDB dass Anfangs die DB noch leer ist und man erst Tabellen anlegen muss um damit zu arbeiten.

Allerdings könnte man auch ein Datenbankgrundgerüst mit der Anwendung mitliefern und spart sich so den Aufwand die Tabellen beim ersten mal mit der Anwendung erstellen zu müssen.

- Alex


----------



## PollerJava (1. Okt 2007)

es steht in meiner Konfig- XML- Datei z.B:



```
<Element type="TrendVariable" 					id="0"				name="KW1_T1_Wasser"> 
		<varID type="initVar" id="0"> 
			<State id="0">		
...	
      		</State>
        </varID>
    </Element>
	<Element type="TrendVariable" 					id="0"				name="KW1_T1_Leistung"> 
		<varID type="initVar" id="0"> 
			<State id="0">
...
      		</State>
        </varID>
    </Element> 
	<Element type="TrendVariable" 					id="0"				name="KW1_T1_Drehzahl"> 
		<varID type="initVar" id="0"> 
			<State id="0">
...
      		</State>
        </varID>
    </Element>
```

Ich lese zuerst meine Konfig.XML in eine List ein und laufe diese List dann durch und schaue wieviel "Variablen" es gibt  und lege eben im oberen Fall 3 Tabellen mit dem namen=... an,





ja, das habe ich soweit jetzt verstanden,
was mir noch unklar ist, ist, wie du schreibst, dass Objekte in die DB gespeichert und von der DB geholt werden, 
ich habe in meiner DB aber nur 


```
stmt = getDBConnection().prepareStatement(String.format("SELECT zeitstempel, wert FROM %s WHERE zeitstempel BETWEEN ? AND ?", dBName));
 
stmt = dBDriver.getDBConnection().prepareStatement(String.format("INSERT INTO %s (Kommen, Gehen, Quit, AlarmNr, Var1, Var2) VALUES ( ?, ?, ?, ?, ?, ?)", tableName));

stmt = dBDriver.getDBConnection().prepareStatement(String.format("UPDATE %s SET Quit = ? WHERE Kommen = ? AND AlarmNr = ? ", tableName));
```

Ich muss mir das erst ansehen, wie ich das dann der SqlMap übergebe, ich hoffe das funktioniert,

bin momentan beim erstellen der XML- Datei mit dem Tutorum (mit 12 Seiten) von maki, das mit den 9 Seiten von Alex hab ich schon gelesen,

lg


----------



## tuxedo (1. Okt 2007)

Mir scheint du stehst total auf dem Schlauch und hast noch nicht verstanden wozu iBatis und Co. gut ist. 

Nochmal im aller Kürze:

iBatis und Co speichern keine Java-Objekte in der DB. diese Tools machen nur ein "mapping". D.h. du kannst Eigenschaften, Daten, Zahlen, Texte, .. aus der DB lesen und sie einem Objekt zuordnen. Beispielsweise "Person".

Magisches Wort ist hierbei "mapping".

- Alex


----------



## PollerJava (2. Okt 2007)

JA heute ist mir schon vieles klarer aber noch nicht alles,
Dankeschön für Eure Geduld, das ist ein neues Thema für mich,

lg


----------

