Hab da ein Problem. Hab ein Fremdschlüssel in der Tabelle user und wenn ich ein Acc erstelle, dann müsste der Primärschlüssel von der Tabelle Adresse in die Tabelle user geschrieben werden. Ich dachte das passiert automatisch, weil beim erstellen der Datenbank die referentielle integrität berücksichtigt wurde und dennoch Passiert es nicht. Es kommt immer der Fehler "Field 'ad_idadresse' doesn't have a default value in table user". Die beiden Tabellen die ich erstelle https://hastebin.com/upacobakab.sql und INSERT Befehle(Arbeite mit JavaFX) https://hastebin.com/hahuvigabu.sql
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 einen alternativen Browser verwenden.
Du solltest ein Upgrade durchführen oder einen alternativen Browser verwenden.
Java Zugewiesener Fremdschlüssel einsetzen
- Ersteller Injector
- Erstellt am
Dachte halt das passiert automatisch von mysql selber, aber anscheinend nicht. Wie müsste ich daran gehen , damit der richtige Fremdschlüssel Wert eingesetzt wird?benneque schrieb:In deinem Code setzt du den Fremdschlüssel doch überhaupt nicht. Woher soll der Code wissen, welche Adresse du da referenzieren willst? Die Sportart nennt sich immer noch Programmieren und nicht Zauberei.
Nein, sowas geht nicht automatisch. Du könntest ja auch erst 10 Adressen erstellen, und danach nur 5 User. Woher soll die Datenbank nun wissen, welche Adresse zu welchem User gehört?
Ich hab ewig nicht mehr mit SQL Statements in Java gearbeitet...
Auf jeden Fall musst du dir vom "connection.prepareStatement(insertAddress)" den von der Datenbank erzeugten Schlüssel geben lassen. Hier hatte jemand dieselbe Frage: https://stackoverflow.com/questions/4246646/mysql-java-get-id-of-the-last-inserted-value-jdbc
Und danach benutzt du diesen Schlüssel beim INSERT für den User als zusätzlichen Parameter.
Ich hab ewig nicht mehr mit SQL Statements in Java gearbeitet...
Auf jeden Fall musst du dir vom "connection.prepareStatement(insertAddress)" den von der Datenbank erzeugten Schlüssel geben lassen. Hier hatte jemand dieselbe Frage: https://stackoverflow.com/questions/4246646/mysql-java-get-id-of-the-last-inserted-value-jdbc
Und danach benutzt du diesen Schlüssel beim INSERT für den User als zusätzlichen Parameter.
Anscheinend hast Du eine Relation falsch abgebildet.Injector schrieb:Hab ein Fremdschlüssel in der Tabelle user und wenn ich ein Acc erstelle, dann müsste der Primärschlüssel von der Tabelle Adresse in die Tabelle user geschrieben werden.
Im Normalfall legt man erst einen User an und erfasst anschließend dessen Adresse. Zum Zeitpunkt des User Anlegens gibt es also noch keine Adresse, deren Referenz man in die User-Tabelle eintragen könnte. Von daher wäre es eigentlich logisch, in der Adressen-Tabelle einen Verweis mit referentieller Integrität auf die User-Tabelle anzulegen und nicht umgekehrt. Denn man erfasst die Adresse zum User.
Es mag zwar Anwendungsfälle geben, wo das anders ist, aber das ist anscheinend bei Dir nicht der Fall, sonst wärst Du nicht auf dieses Problem gestoßen.
@Andreas_ Die Reihenfolge hängt vom UseCase ab. Z.B. könnte er auch ein System bauen, das wahllos Adressen sammelt und diese dann nachträglich den Usern zuordnet werden. (Ist natürlich ziemlich an den Haaren herbei gezogen - ich wollte nur aufzeigen, dass man ohne tiefere Kenntnis der Domain keine Rückschlüsse auf die korrekte Reihenfolge ziehen kann.)
Außerdem kann es noch sein, dass seine Adress Objekte von anderen Tabellen mitgenutzt werden. Hier könnte man dann natürlich auch für die anderen Tabellen jeweils eigene Adress Tabellen erstellen - bis dann jemand "Normalform" schreit . Es gibt halt nicht "die eine Lösung" für Datenmodellierung.
Grundsätzlich könnte er auch einfach beide Statements innerhalb einer Transaktion ausführen, um die Integrität zu gewährleisten.
Außerdem kann es noch sein, dass seine Adress Objekte von anderen Tabellen mitgenutzt werden. Hier könnte man dann natürlich auch für die anderen Tabellen jeweils eigene Adress Tabellen erstellen - bis dann jemand "Normalform" schreit . Es gibt halt nicht "die eine Lösung" für Datenmodellierung.
Grundsätzlich könnte er auch einfach beide Statements innerhalb einer Transaktion ausführen, um die Integrität zu gewährleisten.
Raijin
Fleet Admiral
- Registriert
- Nov. 2007
- Beiträge
- 18.285
Dass eine Datenbank nicht hellsehen kann und einfach die letzte Adress-ID einfügt, wurde ja schon geschrieben. Es wäre fatal, wenn dem so wäre, weil das ggfs falsche Datensätze zur Folge hätte. Wenn, dann muss man der Spalte einen Default Value geben, der ja auch in der Fehlermeldung erwähnt wird. Das könnte beispielsweise eine Dummy-Adresse sein. Ob das sinnvoll ist, sei mal dahingestellt.
In welcher Tabelle der Fremdschlüssel auf die andere Tabelle referenziert hängt von der Kardinalität ab. Soll ein User potentiell mehrere Adressen haben können (1:n) oder kann eine Adresse mehreren Usern zugeordnet werden (n:1)? Das kann man anhand der Code-Schnipsel nicht beurteilen, weil das vom Anwendungsfall abhängt. Es wäre neben den genannten 1:n bzw. n:1 Beziehungen auch eine m:n Beziehung möglich - zB Ehepartner/Familien mit mehreren Wohnsitzen - was dann aber die obligatorische Verknüpfungstabelle nach sich zieht.
Handelt es sich gar um eine 1:1 Beziehung, gehört die Adresse sogar direkt in die User-Tabelle und nicht in eine separate Tabelle.
In welcher Tabelle der Fremdschlüssel auf die andere Tabelle referenziert hängt von der Kardinalität ab. Soll ein User potentiell mehrere Adressen haben können (1:n) oder kann eine Adresse mehreren Usern zugeordnet werden (n:1)? Das kann man anhand der Code-Schnipsel nicht beurteilen, weil das vom Anwendungsfall abhängt. Es wäre neben den genannten 1:n bzw. n:1 Beziehungen auch eine m:n Beziehung möglich - zB Ehepartner/Familien mit mehreren Wohnsitzen - was dann aber die obligatorische Verknüpfungstabelle nach sich zieht.
Handelt es sich gar um eine 1:1 Beziehung, gehört die Adresse sogar direkt in die User-Tabelle und nicht in eine separate Tabelle.
So sieht es in Workbench aus. 1 oder mehrere User können nur in der eine Wohnung(Adresse) leben und die eine Wohnung(Adresse) kann von mehreren User bewohnt werden. So ist es doch eigentlich richtig oder nicht?.
Raijin
Fleet Admiral
- Registriert
- Nov. 2007
- Beiträge
- 18.285
Das ist eine 1:n Relation, ja. Wenn das den Anforderungen entspricht - das weißt ja nur du - dann ist das so richtig. Es können beliebig viele User ein und dieselbe Adress-ID haben und somit am selben Ort leben (zB 10-stöckiges Wohngebäude).
Sollte jedoch ein User einen Zweitwohnsitz, der von Interesse ist, haben, kann das so nicht abgebildet werden, weil der User dann ja zwei Adress-IDs bräuchte. Dann müsste man eine m:n Referenztabelle einfügen. Ob das sinnvoll bzw. notwendig ist, kann man von außen nicht beurteilen. Ein Immobilienmakler zB hätte durchaus Interesse an allen Wohnsitzen bzw. Immobilien seiner Kunden und würde daher eher andersherum denken und einem User mehrere Adressen zuordnen (dann wäre die User-ID in der Adresstabelle). Kämen allerdings auch gemeinschaftliche Immobilien hinzu - zB Ehepartner, die als einzelne User geführt sind - dann müsste man in der Tat eine m:n Referenz aufbauen, weil dann beispielsweise Wohnung 1 und 2 Hänsel und Gretel gehören, Wohnung 3 hingegen nur Gretel.
Sollte jedoch ein User einen Zweitwohnsitz, der von Interesse ist, haben, kann das so nicht abgebildet werden, weil der User dann ja zwei Adress-IDs bräuchte. Dann müsste man eine m:n Referenztabelle einfügen. Ob das sinnvoll bzw. notwendig ist, kann man von außen nicht beurteilen. Ein Immobilienmakler zB hätte durchaus Interesse an allen Wohnsitzen bzw. Immobilien seiner Kunden und würde daher eher andersherum denken und einem User mehrere Adressen zuordnen (dann wäre die User-ID in der Adresstabelle). Kämen allerdings auch gemeinschaftliche Immobilien hinzu - zB Ehepartner, die als einzelne User geführt sind - dann müsste man in der Tat eine m:n Referenz aufbauen, weil dann beispielsweise Wohnung 1 und 2 Hänsel und Gretel gehören, Wohnung 3 hingegen nur Gretel.
mental.dIseASe
Lieutenant
- Registriert
- Dez. 2008
- Beiträge
- 672
Wenn diese Modellierung in deinem Anwendungsfall wichtig ist, du also wirklich erkennen können musst, ob User an der gleichen Adresse wohnen, dann ist das so richtig. Ansonsten würde ich die Adressfelder immer beim User selbst platzieren.
Komplexität nur dort einbauen, wo es erforderlich ist.
Komplexität nur dort einbauen, wo es erforderlich ist.
Ich hab es jetzt so versucht und das geht auch beim ersten mal, wenn die Datenbank eine Datensätze hat aber beim 2. mal geht es nicht mehr, da er halt immer mehrere IDs auswählt. Wie müsste ich das anpassen?
Java:
String insertUser = "INSERT INTO user(vorname,nachname,telefon,passwort,email,ad_idadresse) VALUES(?,?,?,?,?,(SELECT idadresse FROM adresse a,user u WHERE a.idadresse=u.iduser))";
Das kann nicht funktionieren: "WHERE a.idadresse=u.iduser"
Wenn du eine Adresse in der Datenbank angelegt hast, dann existiert idadresse. Aber halt auch erst nachdem sie in der Datenbank angelegt wurde.
Dasselbe gilt für iduser. Aber du versuchst nun auf iduser zuzugreifen während du ebendiesen User anlegst.
Abgesehen davon ist die Vorgehensweise überhaupt nicht zu empfehlen! Du verlässt sich darauf, dass in beiden Tabellen immer dieselben IDs in derselben Reihenfolge erstellt werden. Das mag natürlich bei so einem kleinen einfachen Projekt funktionieren, aber grundsätzlich muss man sagen: Lern es gleich richtig. Pfusch Software kann keiner gebrauchen, sonst passieren noch mehr solche Daten-"Unfälle".
Ich hatte dir oben eine Frage/Antwort von StackOverflow verlinkt. Dort steht, wie du an den Primärschlüssel nach dem Anlegen eines Datensatzes kommst.
Wenn du eine Adresse in der Datenbank angelegt hast, dann existiert idadresse. Aber halt auch erst nachdem sie in der Datenbank angelegt wurde.
Dasselbe gilt für iduser. Aber du versuchst nun auf iduser zuzugreifen während du ebendiesen User anlegst.
Abgesehen davon ist die Vorgehensweise überhaupt nicht zu empfehlen! Du verlässt sich darauf, dass in beiden Tabellen immer dieselben IDs in derselben Reihenfolge erstellt werden. Das mag natürlich bei so einem kleinen einfachen Projekt funktionieren, aber grundsätzlich muss man sagen: Lern es gleich richtig. Pfusch Software kann keiner gebrauchen, sonst passieren noch mehr solche Daten-"Unfälle".
Ich hatte dir oben eine Frage/Antwort von StackOverflow verlinkt. Dort steht, wie du an den Primärschlüssel nach dem Anlegen eines Datensatzes kommst.
parats
Lieutenant
- Registriert
- Okt. 2018
- Beiträge
- 731
Referentielle Integrität bedeutet nicht, dass die DB für dich bei Inserts automatisch referenziert, woher soll sie das wissen? Viel mehr geht es darum, dass deine Tabellen keine toten Schlüssel aufweisen. Bedeutet, dass du bspw. aus einer Dimension keinen Eintrag löschen kannst, der in einer referenzierten Fakten-Tabelle noch vorhanden ist.
Zuletzt bearbeitet:
Hab ich ganz überlesen, danke dir jetzt geht es genau so wie ich es haben wollte. Hier der Code, dass bestimmt ein paar helfen wird.benneque schrieb:Das kann nicht funktionieren: "WHERE a.idadresse=u.iduser"
Wenn du eine Adresse in der Datenbank angelegt hast, dann existiert idadresse. Aber halt auch erst nachdem sie in der Datenbank angelegt wurde.
Dasselbe gilt für iduser. Aber du versuchst nun auf iduser zuzugreifen während du ebendiesen User anlegst.
Abgesehen davon ist die Vorgehensweise überhaupt nicht zu empfehlen! Du verlässt sich darauf, dass in beiden Tabellen immer dieselben IDs in derselben Reihenfolge erstellt werden. Das mag natürlich bei so einem kleinen einfachen Projekt funktionieren, aber grundsätzlich muss man sagen: Lern es gleich richtig. Pfusch Software kann keiner gebrauchen, sonst passieren noch mehr solche Daten-"Unfälle".
Ich hatte dir oben eine Frage/Antwort von StackOverflow verlinkt. Dort steht, wie du an den Primärschlüssel nach dem Anlegen eines Datensatzes kommst.
Java:
String insertAddress = "INSERT INTO adresse(ort,stadt,strasse) VALUES(?,?,?)";
pst0 = connection.prepareStatement(insertAddress,Statement.RETURN_GENERATED_KEYS);
pst0.setString(1, place.getText());
pst0.setString(2, city.getText());
pst0.setString(3, street.getText());
pst0.executeUpdate();
rs=pst0.getGeneratedKeys();
if (rs.next()){
this.id=rs.getInt(1);
}
String insertUser = "INSERT INTO user(vorname,nachname,adrs_idadresse) VALUES(?,?,"+id+")";
pst0 = connection.prepareStatement(insertUser);
pst0.setString(1, name.getText());
pst0.setString(2, lastname.getText());
pst0.executeUpdate();
pst0.close();
Ja, das sieht schon deutlich besser aus!
Jetzt gibt's noch Sonderfälle, die du mit einer Transaktion abfangen könntest:
Deine Tabellen Spalten sind vermutlich "VARCHAR(255)" oder ähnliches. Wenn du nun versuchst einen User anzulegen mit mehr als 255 Zeichen im Namen, dann wird zwar dein INSERT für die Adresse ausgeführt, aber beim INSERT für den User gibt's einen Fehler. Danach hast du dann eine Adresse in deiner Datenbank, die zu niemandem gehört.
Mit einer Transaktion stellt die Datenbank sicher, dass beide(!) INSERTs ausgeführt werden. Wenn irgendwo ein Fehler auftritt, dann wird gar kein(!) INSERT ausgeführt.
Jetzt gibt's noch Sonderfälle, die du mit einer Transaktion abfangen könntest:
Deine Tabellen Spalten sind vermutlich "VARCHAR(255)" oder ähnliches. Wenn du nun versuchst einen User anzulegen mit mehr als 255 Zeichen im Namen, dann wird zwar dein INSERT für die Adresse ausgeführt, aber beim INSERT für den User gibt's einen Fehler. Danach hast du dann eine Adresse in deiner Datenbank, die zu niemandem gehört.
Mit einer Transaktion stellt die Datenbank sicher, dass beide(!) INSERTs ausgeführt werden. Wenn irgendwo ein Fehler auftritt, dann wird gar kein(!) INSERT ausgeführt.
Meinst du mit der Funktion rollback() verhindern und die Funktion einfach in der catch Anweisung aufrufen? Hab ich versucht aber der "Fehler" tritt trotzdem aufbenneque schrieb:Ja, das sieht schon deutlich besser aus!
Jetzt gibt's noch Sonderfälle, die du mit einer Transaktion abfangen könntest:
Deine Tabellen Spalten sind vermutlich "VARCHAR(255)" oder ähnliches. Wenn du nun versuchst einen User anzulegen mit mehr als 255 Zeichen im Namen, dann wird zwar dein INSERT für die Adresse ausgeführt, aber beim INSERT für den User gibt's einen Fehler. Danach hast du dann eine Adresse in deiner Datenbank, die zu niemandem gehört.
Mit einer Transaktion stellt die Datenbank sicher, dass beide(!) INSERTs ausgeführt werden. Wenn irgendwo ein Fehler auftritt, dann wird gar kein(!) INSERT ausgeführt.
Zuletzt bearbeitet:
Ja, genau mit rollback(). Du packst im Prinzip deinen ganzen Datenbank Code in einen try-catch-block. Und wenn innerhalb des Codes ein Fehler auftritt springt dein Code automatisch in den catch Block und dort rufst du dann rollback() auf. Und im finally-Block werden dann die Statements und die Connection geschlossen.
Hier kannst du sehen wie es geht: https://www.mkyong.com/jdbc/jdbc-transaction-example/
Hier kannst du sehen wie es geht: https://www.mkyong.com/jdbc/jdbc-transaction-example/
Es waere noch schoen wenn du das nicht so machst mit dem String, sonst kannst du dir Prepared Statement ganz sparen und einfach Strings zusammensetzen. Ja, es funktioniert hier (du nurInjector schrieb:String insertUser = "INSERT INTO user(vorname,nachname,adrs_idadresse) VALUES(?,?,"+id+")";
int
value, den man nicht escapen muss), aber hey - wir wollen das Maximum an Qualitaet im Code, oder?
Zuletzt bearbeitet:
Funktiort nun alles superbenneque schrieb:Ja, genau mit rollback(). Du packst im Prinzip deinen ganzen Datenbank Code in einen try-catch-block. Und wenn innerhalb des Codes ein Fehler auftritt springt dein Code automatisch in den catch Block und dort rufst du dann rollback() auf. Und im finally-Block werden dann die Statements und die Connection geschlossen.
Hier kannst du sehen wie es geht: https://www.mkyong.com/jdbc/jdbc-transaction-example/
Raijin
Fleet Admiral
- Registriert
- Nov. 2007
- Beiträge
- 18.285
Um den richtigen Einwand von @abcddcba noch zu präzisieren : Hintergrund ist die Angreifbarkeit einer Datenbank durch eine sogenannte SQL-Injection. Entweder du hast eher aus Zufall bisher mit parametrisierten Queries gearbeitet oder du bist dir dieser Verwundbarkeit sogar bewusst. Man sollte das dann aber konsequent durchziehen, um potentielle Unfälle zu vermeiden - beispielsweise das banale Ändern des Datentyps von int auf string und schon hat man ein Problem.
Falls dir der Begriff SQL-Injection nicht geläufig ist, kannst du bei Wikipedia nachlesen worum es geht. Das ist eine der größten und gefährlichsten Schwachstellen einer Datenbankanwendung.
Falls dir der Begriff SQL-Injection nicht geläufig ist, kannst du bei Wikipedia nachlesen worum es geht. Das ist eine der größten und gefährlichsten Schwachstellen einer Datenbankanwendung.
Ähnliche Themen
- Antworten
- 5
- Aufrufe
- 1.246
- Antworten
- 5
- Aufrufe
- 2.555