# associate collection with two open sessions



## kdkkdkddkdkkd (11. Jul 2012)

Hallo!

Ich habe ein großes Problem: Ich programmiere eine Konsolenanwendung mit Spring und AOP. Derzeit versuche ich (testweise) auf eine Datenbank zuzugreifen, ein Element abzuholen und dies wieder zu speichern, um zu sehen ob das Transaktionsmanagement funkioniert. Leider bekomme ich aber folgenden Error:
[WR]Exception in thread "main" org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
[/WR]

Dieser Fehler tritt auf bei der UserDaoImpl.saveOrUpdate(u);

Hier meine konfiguration:

```
NewsletterDao ndao = (NewsletterDao) applicationContext.getBean("newsletterDao");
		ndao.saveOrUpdate(ndao.getNewsletterById(0)); //Funktioniert
		Newsletter nltr = ndao.getNewsletterById(0);
		Mandant mandant = nltr.getMandant();
		
		UserDao ud = (UserDao) applicationContext.getBean("userDao");
		User u = ud.getUserByEmail(mandant, "email@email.email");
		System.out.println(u.getAddress());
		ud.saveOrUpdate(u); // HIER FEHLERMELDUNG
```

UserDaoImpl.

```
public void saveOrUpdate(User user) {
		if (user.getAddress().getEmail() == null) {
			user.getAddress().setEmail(user.getEmail());
		}
		getSession().saveOrUpdate(user);
		getSession().saveOrUpdate(user.getAddress());
	}
```

ApplicationContext
[XML]<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util"

	xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
Index of /schema/jee
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
Index of /schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
Index of /schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
Index of /schema/util 
http://www.springframework.org/schema/util/spring-util-2.5.xsd 
">

	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="shopSessionFactory" />
	</bean>

	<bean id="localDataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.postgresql.Driver" />
		<property name="url"
			value="jdbcostgresql://localhost:******" />
		<property name="username" value="***" />
		<property name="password" value="***" />
	</bean>

	<bean id="shopSessionFactory"
		class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource" ref="localDataSource" />
		<property name="mappingResources" ref="shopMappingResources" />
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
				<prop key="hibernate.format_sql">false</prop>
				<prop key="hibernate.show_sql">false</prop>
			</props>
		</property>
	</bean>

	<tx:advice id="txShopAdvise" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="get**" propagation="SUPPORTS" read-only="true" />
			<tx:method name="save**" propagation="REQUIRED" />
			<tx:method name="delete**" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>
	<aop:config>
		<aopointcut id="daoShopTransaction"
			expression="execution(* dao.*Dao.*(..))" />
		<aop:advisor advice-ref="txShopAdvise" pointcut-ref="daoShopTransaction" />
	</aop:config>

	<!-- DAO Shop -->

	<bean id="userDao" class="dao.UserDaoImpl">
		<property name="sessionFactory" ref="shopSessionFactory" />
	</bean>

	<bean id="newsletterDao" class="dao.NewsletterDaoImpl">
		<property name="sessionFactory" ref="shopSessionFactory" />
	</bean>
	<bean id="newsletterFailedReasonTypeDao"
		class="dao.NewsletterFailedReasonTypeDaoImpl">
		<property name="sessionFactory" ref="shopSessionFactory" />
	</bean>
	<bean id="newsletterFailedReasonDao"
		class="dao.NewsletterFailedReasonDaoImpl">
		<property name="sessionFactory" ref="shopSessionFactory" />
	</bean>

	<bean id="shopMappingResources" class="java.util.ArrayList">
		<constructor-arg>
			<list>
.....
			</list>
		</constructor-arg>
	</bean>
</beans>
[/XML]

Ich suche den Fehler nun schon seit 2 Tagen, schön langsam bin ich am Verzweifeln. Wäre echt toll wenn mir jemand sagen könnte, was ich falsch mache :O

Schönen Tag noch


----------



## maki (11. Jul 2012)

Der Fehler sagt aus, dass du versuchst eine Colelction in 2 Sessions zu verwalten.

Du musst entweder dieselbe Session weiterverwenden (im Falle von eine langlebigen Transaktion) oder eben die erste Session schliessen bevor die Colelciton in der 2. Session verwendet wird.


----------



## kdkkdkddkdkkd (11. Jul 2012)

dass das die Fehlermeldung aussagt verstehe ich schon, nur weiß ich nicht wie ich die vorherige Session schließen soll, sie wird ja von aop verwaltet. Das verstehe ich nicht so ganz


----------



## SlaterB (11. Jul 2012)

was steht eigentllich in getUserByEmail()?
ist ja anscheinend die einzige weitere interessante Methode, kommt das mandant-Objekt irgendwie rein?

was passiert wenn du den Code von saveOrUpdate(User user) gleich in die getUserByEmail() reinkopierst,
dort dann auch direkt Exception?

macht es einen Unterschied wenn du auf anscheinend mindestens 3x getSession() verzichtest, nur 1x getSession aufrufst 
und die Session in einer lokalen Variable ablegst und wiederverwendest?


----------



## kdkkdkddkdkkd (11. Jul 2012)

Hallo!

in getUserByEmail steht:

```
public User getUserByLogin(Mandant mandant, String login) {
		User user = null;
		if (mandant != null) {
			String userlogin = login.trim().toLowerCase();
			user = (User)getSession().createQuery("from User u left join fetch u.addresses a where lower(ltrim(rtrim( u.login ))) = :login and u.mandant.id=:mand_id").setParameter("mand_id", mandant.getId()).setParameter("login", userlogin).uniqueResult();
		}
		return user;
	}
```

wenn ich den saveOrUpdate code in die getUserByEmail reinkopiere erhalte ich den gleichen Fehler.

Wie hast du die letzte Methode gemeint? Im Dao oben Session s = getSession(); aufrufen und mit s weiterarbeiten? Das gibt einen nullpointer :/


----------



## SlaterB (11. Jul 2012)

na du benutzt doch getSession() reichlich, dann müsste es da ja auch Nullpointer geben,
natürlich nicht ganz zu Beginn aufrufen, sondern in der Methode, wenn sowieso verwendet, aber nur einmal statt mehrmals

ich frage mich ob nur einmal getSession() hilft, dass alles zusammenarbeitet,
wenn ja oder nein, richtig was draus ablesen kann ich eher nicht

noch so eine komische Frage:
wenn du die Session in einer Variablen gespeichert hast,
bringt es etwas, vor dem Laden mit clear() den Cache der Session zu leeren?


----------



## kdkkdkddkdkkd (11. Jul 2012)

blöde frage, aber ich benutz doch getSession() in den Daos. Aufgerufen wird das ganze im Main, wenn ich in der Funkion im Main eine Sessionvariable erstelle bringt mir das doch nichts, da die Daos ja uf die Session zugreifen die ich per AOP erstellt habe?!

oder verstehe ich das jetzt irgendwie falsch?


----------



## SlaterB (11. Jul 2012)

'in der Funkion im Main' ist ziemlich ungenau, da weiß ich nicht was du meinst,

ganz klar sind drei Stellen bekannt: die Methode getUserByEmail(), die Methode saveOrUpdate(User) + der Aufrufer dieser beiden, meinetwegen 'main',
dass du den Code von saveOrUpdate(User) nach getUserByEmail() (für diesen Test) kopieren solltest, habe ich gesagt und hast du verstanden,

nun gibt es die 'main', die lediglich die Methode aufruf, und getUserByEmail(), in welcher 3x getSession() steht,
und ich schlage weiter vor, diese drei Aufrufe durch eine lokale Variable zu ersetzen,
jetzt kommst du auf die Idee, in 'main' getSession() aufzurufen? wo diese Methode wahrscheinlich gar nicht definiert ist?
mir unverständlich, natürlich meine ich innerhalb der Methode getUserByEmail(), da wo der ganze Code steht um den es geht..

dort steht

```
getSession().query()
getSession().saveOrUpdate(user);
getSession().saveOrUpdate(user.getAddress());
```
usw., außerdem hast du eine Fehlermeldung 'two open sessions',
es ist doch naheliegend, das mal nur mit garantiert einem Session-Objekt zu probieren

höchstwahrscheinlich bringt das absolut nichts, hätte ich nicht noch anderes zu posten gehabt hätte ich das gar nicht erst gefragt,
die ganzen Rückfragen und Ausbreitung des Themas sind mir unangenehm, denn es wird wohl zu nichts führen


----------



## kdkkdkddkdkkd (11. Jul 2012)

Entschuldige, ich glaube wir haben etwas aneinander vorbei geredet...

Ich versuche es nochmal zu erklären:

Es handelt sich um eine Konsolenanwendung, im Main wird eine Methode aufgerufen (public static void writeValidation()), welche zum einen die Daos vom ApplicationContext holt (Code-Snippet aus dem ersten Post) und dann über diese Daos einen User holt, den dann auch wieder Speichert (zu Testzwecken).

Wie schon erwähnt habe ich per Spring die sessionFactory in jede DaoBean injected (um im Dao mit getSession().* arbeiten zu können) und per AOP habe ich das Transectionmanagement realisiert (Transaction immer bei get**, save**, delete**). 

Entschuldige falls ich deinen Post falsch verstanden haben sollte, aber ich bin durch die ganze Fehlersucherei schon etwas verwirrt.

Hoffe ihr könnt mir trotzdem noch helfen


----------



## kdkkdkddkdkkd (12. Jul 2012)

Ein kleines Update meinerseits:

funktioniert nun, ich habe (wie SlaterB gesagt hat) in der UserDao die Session zu beginn in eine Variable gespeichert und statt dauernd getSession() aufzurufen immer diese Variable verwendet. 
Ein weiteres Problem das ich etndeckt habe ist, dass erst in die DB geschrieben wird, wenn ich ein beginTransaction() und ein commit() hinzufüge. Das zeigt doch meines erachtens klar, dass bei der config von AOP, speziell beim TransactionManager, etwas nicht in Ordnung ist?!

Liebe Grüße


----------



## SlaterB (12. Jul 2012)

das mit den unterschiedlichen Sessions sehe ich kritisch, auch wenn ich trotz der Idee nicht viel mehr dazu sagen kann,

die Abhängigkeit von der Transaktion kenne ich so auch aus Hibernate, ist für mich ok, einfach dran halten


----------



## kdkkdkddkdkkd (12. Jul 2012)

hab nun auch das Problem mit den Transaktionen beseitigt (mit der Annotation @Transactional). 

Nun bleibt nur mehr das problem mit den Sessions. Was mich wundert ist der Fakt, dass ich das eigentlich immer so gemacht habe in den Daos mit getSessio(),saveOrUpdate(..) und es hat eigentlich nie den Fehler mit den multiple Sessions geworfen :O


----------



## kdkkdkddkdkkd (16. Jul 2012)

Hallo!
Hab das Problem gelöst. Für alle die den selben Fehler haben hier meine Fehlerquelle:

Der Fehler lag grundsätzlich in den Mappings. Im PoJo wurde die Spalte ID mit integer initialisiert, im hbm.xml aber mit long (dürfte ein Fehler beim reverse-engineering passiert sein). Was mich wundert ist, dass Eclipse das nicht angezeigt hat. Nichtsdestotrotz, nach ausbessern dieser Ungleichheiten funktioniert es. 

Kann nun auf Erledigt gesetzt werden. Danke!


----------

