Java Hibernate Exception wegen "two open Sessions"

cl0udt

Lt. Junior Grade
Registriert
Sep. 2008
Beiträge
508
Hallo zusammen,

ich bekomme beim Versuch einen Benutzer aus der Datenbank zu löschen, leider immer die Exception: "Illegal attempt to associate a collection with two open sessions".

Ausgangssituation ist die folgende:


In der Klasse searchUser wird ein User in der Datenbank gesucht. Dieser wird dann, falls ein User gefunden wird, angezeigt in einer Liste und mit einem Link versehen. Beim Klicken auf den Link, wird eigentlich eine neue Form geladen, aber das hab ich hier rausgelassen, um den Code nicht noch länger zu machen. Momentan wird der angeklickte User nur gelöscht, bzw. sollte gelöscht werden. Beim Klicken auf den Link kommt die Exception.
Code:
public class SearchUser extends BasePage {

	@SpringBean(name="userDao")
	UserDao userdao;
	
	List<User> userList;

	/**
	 * Constructor of this Class
	 */
	public SearchUser() {
		super();
		createSearchbar();
		
    }

	/** Creates the Searchbar */
	private void createSearchbar() {
		
		/* container which holds table */ 
		final WebMarkupContainer wmc2 = new WebMarkupContainer("table");
		add(wmc2);
		wmc2.setVisible(false);
		
		/* Creates Searchbar  */
		FeedbackPanel feedbackPanel = new FeedbackPanel("feedback");
		add(feedbackPanel);
		final TextField<String> searchUser = new RequiredTextField<String>("searchUser", new Model<String>()); 
		
		
		// Add a form
		Form form = new Form("searchForm"){

			protected void onSubmit() {
				/*	Searches for the given String */
				userList = new ArrayList<User>();
				userList = userdao.searchByEmail(searchUser.getValue());
				wmc2.setVisible(true);
				if (userList.size() < 1) userList = userdao.searchByLastname(searchUser.getValue());
				if (userList.size() < 1) userList = userdao.searchByForename(searchUser.getValue());
				if (userList.size() < 1) { info("Kein Kunde gefunden"); wmc2.setVisible(false); }
				
			}
		};

		
		
		
		// wraps the list of Users into an IModel
		IModel<List<User>> userListModel = new LoadableDetachableModel<List<User>>(userList) {

			@Override
			protected List<User> load() {
				
				return userList;
			}
		}; 
		
		// Creates new List with the Users
		ListView<User> list = new ListView<User>("userList", userListModel) {

			@Override
			protected void populateItem(ListItem item) {
				
				// get "clicked" user
				final User user = (User) item.getModelObject();
				
				Link link1 = new Link("usernameLink") {

					@Override
					public void onClick() {
                                                // DAS IST DIE KRITISCHE METHODE
						userdao.delete(user);
						
					}
				};
				
				link1.add(new Label("usernameLabel", user.geteMail()));
				item.add(link1);
				item.add(new Label("idLabel", user.getId().toString()));
				
				
			}
		};
		
		setOutputMarkupId(true);
		add(list);
		form.add(searchUser);
		add(form);
		
	}
}

Hat vielleicht irgendjemand eine Idee, was ich falsch mache? Hab bei Google einige Seiten mit dieser Exception gefunden und auch vieles ausprobiert, leider hat mir nichts wirklich weitergeholfen. Vielleicht sieht ja jemand, der Erfahrung mit Hibernate hat, relativ schnell den Fehler. Ich kann mir nicht wirklich erklären, wieso 2 Sessions geöffnet sein sollen...

Danke schonmal für die Hilfe!




Anbei mal der interessante Teil vom Stacktrace, falls es vielleicht jemandem etwas sagt:
Unexpected RuntimeException

Last cause: Illegal attempt to associate a collection with two open sessions
WicketMessage: Method onLinkClicked of interface org.apache.wicket.markup.html.link.ILinkListener targeted at [ [Component id = usernameLink]] on component [ [Component id = usernameLink]] threw an exception

Stacktrace

Root cause:

org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
at org.hibernate.collection.internal.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:565)
at org.hibernate.event.internal.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:65)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:121)
at org.hibernate.event.internal.AbstractVisitor.processValue(AbstractVisitor.java:82)
at org.hibernate.event.internal.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:76)
at org.hibernate.event.internal.AbstractVisitor.process(AbstractVisitor.java:143)
at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:121)
at org.hibernate.event.internal.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:74)
at org.hibernate.internal.SessionImpl.fireDelete(SessionImpl.java:946)
at org.hibernate.internal.SessionImpl.delete(SessionImpl.java:925)
 
Zuletzt bearbeitet:
Also bin jetzt kein Java Profi... aber soweit ich verstanden habe läds du Userdaten aus der HTML Seite?

Wäre es nicht einfach WebServices zu benutzen oder Direkt mit der DB zu unteragieren?
 
Hi,

danke erstmal für deine Antwort.

Ich lade den User aus der Datenbank, indem ich ihn mit der Methode "searchByEmail" aus Zeile 37 suche. Zuvor muss natürlich im Textfeld ein String eingegeben worden sein, nachdem gesucht werden soll.
Ich lasse mir in die ArrayList von Usern dann die gefundenen User laden und zeige sie in einer ListView (Liste aus dem Wicket-framework) auf der Webpage an.

In meinem vereinfachten Beispiel picke ich den User raus, den ich angeklickt habe auf der Webpage und will ihn einfach löschen. Das soll jetzt hier keinen besonderen sinn ergeben. Eigentlich wird eine neue Seite aufgerufen, mit einem Formular in dem der User geändert und wieder abgespeichert werden kann.

Ich habe, wie gesagt, das Ganze etwas vereinfacht. Beim Klick auf den User, soll der User einfach gelöscht werden. Aber dabei tritt leider die Fehlermeldung auf.


P.S.: Ich benutze Hibernate aufgrund diverser Vorteile, die es bietet :). Vereinfacht einige Sachen einfach ziemlich.
 
Zuletzt bearbeitet:
Schwer zu sagen was bei dir jetzt genau das Problem sein kann. Arbeite jetzt selbst nicht mit Hibernate + Swing. Das der Code faktisch unverwendendbar ist macht die Sache nicht leichter.
Vielleicht ist das Object detached dann würd ein merge helfen.
 
Woran siehst du das er mit Swing arbeitet oder meinst du Spring :)?

Irgendwo in deinem DAO wird wahrscheinlich ein entitymanager#update aufgerufen, da wirst du ein merge brauchen-->Vermutung.
 
Er benutzt Apache Wicket als front end framework. Da ist die ListView einer der repeater, mit denen man sich wiederholendes markup rendern kann, wie z.B. eine Auflistung von Benutzern.

Ich kann hier auch nur spekulieren. Ich weiß nicht, wie die injection des DAO funktioniert, d.h. wann und wie oft diese stattfindet. Wenn du beim Drücken des Links eine neue Session injected bekommst aber die alte noch irgendwie von der Seite festgehalten wird, könnte das zu dem Problem führen, das auch in dem stackoverflow-Beitrag besprochen wurde.
Aber alles reine Spekulation meinerseits. Vielleicht versuchst du mal das DAO in ein LoadableDetachableModel zu verpacken, damit es zwischendurch detached wird.
 
Zuletzt bearbeitet:
Hab einiges ausprobiert und nun klappt es. Die Lösung war wirklich die Vermutung von "Schaltnetze" und die Quelle war auch sehr hilfreich. Musste mergen, dann hat es funktioniert.
Also, falls nochmal jemand anderes das gleiche Problem hat, die folgende Codezeile hat mein problem gelöst:

Code:
                //tempUser ist der User, den ich aus dem Suchformular geladen habe und der sich
                // nicht löschen ließ
		Session session = userdao.getSession();
		User user = (User) session.merge(tempUser);
	        Transaction tx = session.beginTransaction(); 
	        session.update(user);
		tx.commit();

Bin mir zwar nicht sicher, ob ich das jetzt so 100%ig richtig angewendet habe, werde da nochmal bissl rumprobieren, aber hat jetzt erstmal funktioniert.

Vielen Dank an alle!!!
 
Zurück
Oben