Die erste Behauptung geht, die zweite schlägt fehl. Ich habe einen anderen Test ausprobiert, der den Tokenwert ändert und in der Datenbank speichert, und er funktioniert tatsächlich, daher bin ich mir nicht sicher, warum das Löschen nicht funktioniert. Es löst auch keine Ausnahmen aus, sondern speichert es nur nicht in der Datenbank. Es funktioniert auch nicht gegen meine Oracle-Datenbank.
Bearbeiten
Habe immer noch dieses Problem. Ich konnte den Löschvorgang in der Datenbank beibehalten, indem ich dies zu meiner TokenRepository-Schnittstelle hinzufügte:
@Modifying
@Query("delete from Token t where t.id = ?1")
void delete(Long entityId);
Dies ist jedoch keine ideale Lösung. Irgendwelche Ideen, was ich tun muss, damit es ohne diese zusätzliche Methode funktioniert?
hast du dafür schon mal eine lösung gefunden? gleiches Problem auch in der allerneuesten Frühjahrsversion. laut mysql-protokolltabelle wird niemals eine löschanweisung ausgegeben, keine fehlermeldung verfügbar.
– phil294
7. August 2018 um 13:50 Uhr
Unglücklicherweise nicht. Ich musste es hier nicht mehr tun und die anderen Orte, an denen ich es tun musste, schienen gut zu funktionieren. Ich weiß nicht, was an diesem Fall so besonders war.
– Twisty McGee
7. August 2018 um 17:04 Uhr
Sie sollten in Betracht ziehen, diese @Modifying-Löschanweisung als Antwort zu posten. Nur so konnte ich es auch lösen. Ich habe die Frage positiv bewertet, aber ich würde auch diese Antwort positiv bewerten.
– Taugenichts
15. Juli 2019 um 21:27 Uhr
Das Überschreiben der Löschmethode(n) hat es auch für mich gelöst, nicht sicher, warum dies passiert ist (Upgrade von Spring Boot 2.1.5 auf 2.1.6)
– Brunaldo
23. Juni 2020 um 15:53 Uhr
Dasselbe Problem hier bei einer einfachsten Entität, die keine Beziehungen verwendet. speichern und dann löschen in einer Transaktion, z. B. funktioniert die Testmethode nicht mehr mit Spring 2.1.6. Wir verwenden jetzt Spring 2.4.1, stufen spring-data jedoch auf 2.1.8.RELEASE herunter, um dies zu umgehen. Hibernate bleibt unverändert 5.4.25.
– JRA_TLL
7. Juni 2021 um 8:39 Uhr
pzeszko
Höchstwahrscheinlich tritt ein solches Verhalten auf, wenn Sie eine bidirektionale Beziehung haben und nicht beide Seiten synchronisieren, WÄHREND Elternteil und Kind bestehen bleiben (an die aktuelle Sitzung angehängt).
Das ist knifflig und ich werde dies mit dem folgenden Beispiel erklären.
@Entity
public class Parent {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Long id;
@OneToMany(cascade = CascadeType.PERSIST, mappedBy = "parent")
private Set<Child> children = new HashSet<>(0);
public void setChildren(Set<Child> children) {
this.children = children;
this.children.forEach(child -> child.setParent(this));
}
}
@Entity
public class Child {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
private Long id;
@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;
public void setParent(Parent parent) {
this.parent = parent;
}
}
Schreiben wir einen Test (übrigens einen transaktionalen)
Ziemlich einfacher Test, oder? Wir erstellen Eltern und Kind, speichern es in der Datenbank, holen dann ein Kind aus der Datenbank, entfernen es und stellen schließlich sicher, dass alles wie erwartet funktioniert. Und das ist es nicht.
Das Löschen hier hat nicht funktioniert, weil wir den anderen Teil der Beziehung nicht synchronisiert haben, nämlich PERSISTED IN CURRENT SESSION. Wenn Parent nicht mit der aktuellen Sitzung verbunden wäre, würde unser Test bestehen, dh
@Component
public class ParentFixture {
...
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void thereIsParentWithChildren() {
Parent parent = new Parent();
Child child = new Child();
parent.setChildren(Set.of(child));
parentRepository.save(parent);
}
}
und
@Test
public void test() {
parentFixture.thereIsParentWithChildren(); // we're saving Child and Parent in seperate transaction
Child fetchedChild = childRepository.findAll().get(0);
childRepository.delete(fetchedChild);
assertEquals(1, parentRepository.count());
assertEquals(0, childRepository.count()); // WORKS!
}
Natürlich beweist es nur meinen Standpunkt und erklärt das Verhalten, mit dem OP konfrontiert war. Der richtige Weg ist offensichtlich, beide Teile der Beziehung synchron zu halten, was bedeutet:
class Parent {
...
public void dismissChild(Child child) {
this.children.remove(child);
}
public void dismissChildren() {
this.children.forEach(child -> child.dismissParent()); // SYNCHRONIZING THE OTHER SIDE OF RELATIONSHIP
this.children.clear();
}
}
class Child {
...
public void dismissParent() {
this.parent.dismissChild(this); //SYNCHRONIZING THE OTHER SIDE OF RELATIONSHIP
this.parent = null;
}
}
Offensichtlich @PreRemove könnte hier verwendet werden.
Wirklich gute Arbeit an der Erklärung hier. Ich hatte das gleiche Problem und die gleiche scheinbare “Problemumgehung” – Löschen durch eine benutzerdefinierte Abfrage, aber ich wollte es nicht verwenden, da es offensichtlich ein Hack war. Der Hook @PreRemove hat hier wirklich Wunder bewirkt. Vielen Dank!
– Ognjen Mišić
31. Oktober 2019 um 10:17 Uhr
Froh, dass ich helfen konnte!
– pzeszko
31. Oktober 2019 um 15:29 Uhr
Ich hatte ein ähnliches Problem mit der @OneToOne-Beziehung und Ihre Erklärung hat mir geholfen, es zu lösen. Sehr schön! Vielen Dank.
– Fahrersti
15. März 2021 um 12:05 Uhr
etwas spät dazu, aber was meinst du in diesem Zusammenhang mit synchronisieren?
– Kelsanität
30. August 2021 um 13:54 Uhr
Ich hatte das gleiche Problem
Vielleicht hat Ihre UserAccount-Entität ein @OneToMany mit Cascade für ein Attribut.
Ich habe gerade die Kaskade entfernt, als könnte sie beim Löschen bestehen bleiben …
Das hat auch bei mir funktioniert. Insbesondere habe ich herumgespielt und konnte diese Kaskadentypen beibehalten: [CascadeType.PERSIST,CascadeType.REFRESH] und trotzdem das Löschen durch das untergeordnete Repository arbeiten lassen. Was für mich keinen Sinn machte, war, dass ich die Eigentümerentität über “mappedBy” auf dem Elternteil zum Kind gemacht habe
– GameSalutes
5. April 2016 um 22:36 Uhr
Diese Lösung scheint zu funktionieren, gibt aber keine Erklärung.
– Ivan Matavulj
8. Mai 2017 um 15:51 Uhr
Taimur
Sie müssen die PreRemove-Funktion in der Klasse hinzufügen, in der Sie viele Objekte als Attribut haben, z. B. in der Bildungsklasse, die eine Beziehung zu UserProfile Education.java haben
private Set<UserProfile> userProfiles = new HashSet<UserProfile>(0);
@ManyToMany(fetch = FetchType.EAGER, mappedBy = "educations")
public Set<UserProfile> getUserProfiles() {
return this.userProfiles;
}
@PreRemove
private void removeEducationFromUsersProfile() {
for (UsersProfile u : usersProfiles) {
u.getEducationses().remove(this);
}
}
Eine Möglichkeit ist die Verwendung cascade = CascadeType.ALL wie folgt in Ihrem userAccount-Dienst:
Dann tun Sie so etwas wie das Folgende (oder eine ähnliche Logik)
@Transactional
public void deleteUserToken(Token token){
userAccount.getTokens().remove(token);
}
Beachten Sie die @Transactional Anmerkung. Dadurch kann Spring (Hibernate) wissen, ob Sie entweder bestehen bleiben, zusammenführen oder was auch immer Sie in der Methode tun. AFAIK das obige Beispiel sollte arbeiten, als ob Sie keinen CascadeType gesetzt hätten, und rufen Sie auf JPARepository.delete(token).
Dies ist für alle, die von Google kommen und wissen, warum ihre Löschmethode nicht funktioniert Spring Boot/Ruhezustandob es aus dem JpaRepository/CrudRepository verwendet wird delete oder aus einem benutzerdefinierten Repository-Aufruf session.delete(entity) oder entityManager.remove(entity).
Ich habe ein Upgrade von Spring Boot 1.5 auf Version 2.2.6 (und Hibernate 5.4.13) durchgeführt und eine benutzerdefinierte Konfiguration für verwendet transactionManageretwas wie das:
@Bean
public HibernateTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new HibernateTransactionManager(entityManagerFactory.unwrap(SessionFactory.class));
}
Und ich habe es geschafft, es mit zu lösen @EnableTransactionManagement und Löschen der Gewohnheit transactionManager Bohnendefinition oben.
Wenn Sie immer noch eine Art benutzerdefinierten Transaktionsmanager verwenden müssen, kann es auch funktionieren, die Bean-Definition in den folgenden Code zu ändern:
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
Als letzte Anmerkung denken Sie daran, die automatische Konfiguration von Spring Boot zu aktivieren entityManagerFactory Bean kann automatisch erstellt werden, und auch alle entfernen sessionFactory Bean, wenn Sie auf upgraden entityManager (Andernfalls führt Spring Boot die automatische Konfiguration nicht richtig durch). Und schließlich stellen Sie sicher, dass Ihre Methoden sind @Transactional wenn Sie Transaktionen nicht manuell bearbeiten.
Lukas Holt
Ich habe das auch gerade durchgemacht. In meinem Fall musste ich die untergeordnete Tabelle mit einem nullbaren Fremdschlüsselfeld versehen und dann das übergeordnete Element aus der Beziehung entfernen, indem ich null setzte und dann save und delete und flush aufrief.
Ich habe vorher kein Löschen im Protokoll oder eine Ausnahme gesehen.
Eruvanos
Wenn Sie eine neuere Version von Spring Data verwenden, können Sie die deleteBy-Syntax verwenden … damit Sie eine Ihrer Anmerkungen entfernen können: P
hast du dafür schon mal eine lösung gefunden? gleiches Problem auch in der allerneuesten Frühjahrsversion. laut mysql-protokolltabelle wird niemals eine löschanweisung ausgegeben, keine fehlermeldung verfügbar.
– phil294
7. August 2018 um 13:50 Uhr
Unglücklicherweise nicht. Ich musste es hier nicht mehr tun und die anderen Orte, an denen ich es tun musste, schienen gut zu funktionieren. Ich weiß nicht, was an diesem Fall so besonders war.
– Twisty McGee
7. August 2018 um 17:04 Uhr
Sie sollten in Betracht ziehen, diese @Modifying-Löschanweisung als Antwort zu posten. Nur so konnte ich es auch lösen. Ich habe die Frage positiv bewertet, aber ich würde auch diese Antwort positiv bewerten.
– Taugenichts
15. Juli 2019 um 21:27 Uhr
Das Überschreiben der Löschmethode(n) hat es auch für mich gelöst, nicht sicher, warum dies passiert ist (Upgrade von Spring Boot 2.1.5 auf 2.1.6)
– Brunaldo
23. Juni 2020 um 15:53 Uhr
Dasselbe Problem hier bei einer einfachsten Entität, die keine Beziehungen verwendet. speichern und dann löschen in einer Transaktion, z. B. funktioniert die Testmethode nicht mehr mit Spring 2.1.6. Wir verwenden jetzt Spring 2.4.1, stufen spring-data jedoch auf 2.1.8.RELEASE herunter, um dies zu umgehen. Hibernate bleibt unverändert 5.4.25.
– JRA_TLL
7. Juni 2021 um 8:39 Uhr