Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Hi,
sorry für die dumme Überschrift.
Ich habe folgendes Problem: Ich bin noch ein Newbie in JAVA und ich habe mal aus Juchs ein kleines Prog gebastelt, wo man sich anmelden, registrieren und die Benutzer anzeigen kann.
Wenn sich nun jemand registriert, wird der Benutzer in der MSAccess-Datenbank 2 mal eingetragen.
ich habe das so rausgelesen (trippel post zum nachobenschieben, mag ich garnicht, dass ist in zukunft zu unterlassen):
keine fehler, doch das ganze ist 2mal eingetragen.
aber man braucht wirklich mehr code um was erkennen zu können
Hi,
wie gesagt, es kommt keine Fehlermeldung. An der Datenbank erkenne ich nur, dass ein User plötzlich 2 mal angetragen wurde.
Ich dachte, dass die anderen Codes nicht relevant sind, aber gut....
Code:
void btStart_actionPerformed(ActionEvent e) {
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
tfStart.setText("Treiber egistriert");
try{
connDB=DriverManager.getConnection("jdbc:odbc:PasswortAbfrage","",""); /*connDB wurde ganz oben deklariert (hier nicht sichtbar) */
tfStart.setText("Verbindung hergestellt");
}
catch (Exception ex){
tfStart.setText("Fehler beim Verbindungsaufbau");
}
}
catch (Exception ex){
tfStart.setText("Fehler beim Registrieren des Treibers");
}
}
Code:
void btLogin_actionPerformed(ActionEvent e) {
String benutzer, passwort, sqlAnweisung;
benutzer=tfBenutzer.getText();
passwort=tfPass.getText();
sqlAnweisung="SELECT Benutzername, Passwort FROM Tabelle1 WHERE Benutzername='"+benutzer + "'";
try{
PreparedStatement pStat; //Erzeugen eines Übergabeobjektes an die DB
pStat=connDB.prepareStatement(sqlAnweisung);
ResultSet rSet;
rSet=pStat.executeQuery(); //SQL-Anweisung ausführen
rSet.next();
if(rSet.getString("Passwort").equals(passwort)){
lbAusgabe.setText("Erfolgreich eingeloggt!");
}
else{
lbAusgabe.setText("Benutzername oder Kenntwort ist falsch");
}
} catch (Exception ex){
lbAusgabe.setText("Fehler beim Lesen der Kundendaten");
}
}
void btAnzeigen_actionPerformed(ActionEvent e) {
String sqlAnzeigen, benutzernamen="";
sqlAnzeigen="SELECT Benutzername FROM Tabelle1 order by benutzername desc";
try{
PreparedStatement pStat; //Erzeugen eines Übergabeobejktes an die DB
pStat= connDB.prepareStatement(sqlAnzeigen);
ResultSet rSet; //Erzeugen eines Rückgabeobejektes zum Speichern der Antworttabelle
rSet= pStat.executeQuery(); //SQL-Anweisung ausführen
while (rSet.next()){ // oder (rSet.next()==true)
benutzernamen=rSet.getString("Benutzername")+ "\n" + benutzernamen;
}
tBenutzer.setText(benutzernamen);
}catch (Exception fa){
tBenutzer.setText("Anzeigen der Benutzer fehlgeschlagen!");
}
}
}
ich kann leider auch keinen Fehler sehen. Was ich aber sehen kann ist, dass
du nicht verstanden hast, wie jdbc funktioniert.
Kennst du den Unterschied zwischen dynamischen und statischem SQL? Weißt du
was execute immediate und prepare execute ist?
Hier ein kleines Bild, was dir schon einmal einen Überblick verschaffen sollte.
Das Bild findest du auf http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odch02pr_7.asp
Der Artikel ist zwar über odbc, aber da odbc sowie jdbc auf dem Standard für SQL CLI (Call-Level Interface) beruhen,
welcher von der X/Open SQL Access Group 1992 vereinbart wurde ist die Implementierung ziemlich identisch.
JDBC ist dynamisches SQL und da gibt es die zwei Varianten execute immediate und prepare execute.
execute immediate
Hierbei handelt es sich um eine Technik bei der das SQL Statement an die Datenbank geschickt wird und dort
alle Ebenen auf einmal durchläuft. Es wird geparst, optimiert, ein Zugriffsplan erstellt und dann wird es ausgeführt.
Das was du bei einem SELECT zurück bekommst ist eine Ergebnismenge. Diese befindet sich aber nicht auf dem Client.
Also in deinem Programm, sondern auf der Datenbank. Was du zurück bekommst ist ein sogenannter Cursor. Dieser
zeigt vor die erste Zeile der Ergebnismenge. Deshalb benutzt man die next-Methode der ResultSet-Klasse um den Cursor
auf die erste Zeile der Ergebnismenge zu bewegen. Solch eine Abfrage, wo man eine Ergebnismenge erwartet wird mit
der executeQuery-Methode ausgeführt.
Es gibt aber auch noch Statements, welche keine Ergebnismenge
liefern. Zum Beispiel bei UPDATE oder INSERT. UPDATE liefert zum Beispiel die Anzahl der geänderten Zeilen.
Für solche Anfragen steht die executeUpdate-Methode zur Verfügung.
Zu guter letzt gibt es auch noch den Fall, dass man nicht weiß, ob eine Ergebnismenge oder nur ein Zahlenwert zurück
gegeben wird. Das kann zum Beispiel dann passieren, wenn du ein Programm schreibst, in dem der Benutzer selbst
SQL-Statements eingeben und ausführen kann. Für solche Fälle ist die execute-Methode vorgesehen. diese gibt einen
boolean zurück. true, wenn die Ausführung des Statements eine Ergebnismenge erzeugt hat und false, wenn entweder ein Zahlenwert oder keine Ergebnismenge zurückgegeben wurde. Wenn du dann weißt, um was es
sich handelt, kannst du mit der getResultSet-Methode dir das ResultSet geben lassen oder mit der
getUpdateCount-Methode den Zahlenwert.
prepare execute
Hierbei wird mit prepare die Datenbank beauftragt, dass SQL-Statement zu parsen, validieren, optimieren und den Zugriffsplan
zu erstellen. Das Statement wird aber noch nicht ausgeführt. Wie die Datenbank das PreparedStatement intern
behandelt ist Implementierung. Meist wird die Datenbank StoredProcedures verwenden. Erst wenn man auf das PreparedStatement die execute, executeUpdate oder executeQuery-Methode aufruft, wird es auf der Datenbank ausgeführt.
Stellt sich jetzt nur noch die Frage wofür das Ganze gut ist.
Nehmen wir an in deiner Anwendung gibt es einen Such-Dialog. Der Benutzer kann hier Suchbegriffe eingeben. Dann
gibt es noch eine Schaltfläche zum Abfragen der Datenbank. Jetzt wäre es von der Performance her ungünstig jedesmal,
wenn der Benutzer auf die Schaltfläche klickt, ein Statement-Objekt sich zu besorgen und dann die executeQuery-Methode
aufzurufen. Warum? Weil nun die Datenbank die ganze Prozedur (parsen, validieren, optimieren, Zugriffsplan, ausführen)
durchführen muss (siehe Bild). Und das bei jeder Abfrage.
Wie nun das Ganze verbessern?
Die Antwort lautet PreparedStatement. Bei der initialisierung des Dialogs beschafft man sich ein PreparedStatement-Objekt
Diesem gibt man nicht den String
Code:
SELECT * FROM Kunden WHERE name='irgendwer'
sondern
Code:
SELECT * FROM Kunden WHERE name = ?
Das ? ist ein Platzhalter. Jetzt kann die Datenbank parsen, validieren, optimieren und den Zugriffsplan erstellen. Und das
nur einmal.
Anschliessend muss man bei einem klick nur die Parameter binden. Das geht mit einer der setXXX-Methoden.
Zum Beispiel.
damit wird der String des TextFields als erster Parameter gebunden. Das bedeutet, dass bei der Ausführung dieser
Parameter an die Stelle des ersten Fragezeichens gesetzt wird. Dann macht man einfach ein executeQuery.
Der Benutzer kann jetzt beliebig viele Suchanfragen stellen ohne das die Performance der Datenbank darunter leidet.
HINWEIS
Gib immer alle Ressourcen wieder frei, wenn du diese nicht mehr brauchst. Wie oben beschriebden, weißt du jetzt ja,
das du damit die Ressourcen auf der Datenbank wieder freigibst. Also nicht denken "Das macht der Garbage Collector schon".
Wann der das macht ist nicht klar. Deswegen solltest du die Datenbank nicht mit dem Verwalten von
Ressourcen aufhalten, die du sowieso nie mehr brauchst.
Also mach einfach ein close auf das Statement oder die jeweilige Ressource.
So jetzt könnte ich dir noch was über Transaktionen und Isolationslevel erzählen, aber dazu habe ich keine Lust mehr.
Such im Internet dort gibt es einiges.
Ich hoffe, dass ich ein wenig Klarheit in das Konzept bringen konnte, welches hinter JDBC steht. Vielleicht wird es
dem Einen oder Anderem hilfreich sein.
Hi Rene! :shock:
Ich lerne JAVA in der Schule (Berufskolleg für Inofrmations- und Kommunikationstechnik) und bin gerade im ersten Jahr und da lernen wir das normalerweise noch (lange) nicht. Deswegen habe ich da noch ein paar Probleme, was das ganze angeht.
Deine Erklärung ist sehr informativ, danke für deine Mühe, jedoch wäre es mir lieber, wenn du mir als Anfänger einen konkreten Hinweis geben würdest.
Danke.