# Hibernate JPA - Synchonisation von Transactions



## Saxony (27. Jan 2010)

Hiho,

ich habe gerade folgendes Problem:

Ich bekomme im Abstand von 50-1000ms neue Daten geliefert aus denen ich Objekte baue. Diese möchte ich dann mittels Hibernate JPA in eine MSSQL 2008 DB wegschreiben. Dazu verwende ich:

[Java]
public static boolean addData(final MyData aData) {

	try {

		final EntityManager em = DBUtil.getEntityManager();

		em.getTransaction().begin();
		em.persist(aData);
		em.getTransaction().commit();

		em.clear();

		return true;

	} catch (final Exception ex) {

		Activator.getDefault().logError("[DB] Problem", ex);
	}

	return false;
}
[/Java]

Dies funktioniert auch für den Großteil der Schreibaktionen - aber jede 4.-5. Schreibaktion erzeugt folgende Exception:


```
java.lang.IllegalStateException: Transaction already active
at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:35)
at myproject.DataDBUtil.addData(DataDBUtil.java:17)
```

Es wird also bei em.getTransaction().begin(); rumgemotzt.

Ich denke mir nun, dass ein vorangegangener Schreibvorgang am laufen ist während schon versucht wird ein neues Objekt in die DB zu schreiben.

Wie kann ich nun die Schreibzugriffe synchronisieren? Damit alles schön NACHEINANDER abgearbeitet wird? Kenne da im Moment keine Best Practice Hibernate JPA betreffend (also Queue, Transaction-Pool, oder was weiß ich) 

Hoffe da weiß jemand bescheid von euch!

bye Saxony


----------



## xerberuz (27. Jan 2010)

Der EntityManager selbst ist nicht thread-safe. Allerdings sieht man bei deinem Code Beispiel nicht ob die Methode von mehreren Threads verwendet wird oder nicht.

Wenn ja, dann hast du 3 Möglichkeiten:
1. Du erzeugst einen EntityManagerfür jeden Thread (java.lang.ThreadLocal) oder verwendest einen Pool
2. Du machst die Methode "addData" synchronized
3. Es gibt nur einen schreibenden Thread, der addData aufruft. Die anderen Threads schieben dem die Daten per Queue zu.

Wenn das nur ein Thread is, der zu diesem Problem führt, könnte es an deinem catch Block liegen. Da sollte so etwas wie 

```
if(em.getTransaction().isActive()) {
 em.rollback();
 em.clear();
}
```

drin sein


----------



## byte (27. Jan 2010)

Wird der EntityManager überhaupt beim commit() geschlossen, wie es z.b. bei der Hibernate Session der Fall ist? Falls nein, dann sollte zusätzlich noch ein 
	
	
	
	





```
finally { em.close };
```
 ans Ende der Methode.

Oder lässt Du den EntityManager ewig offen? Das würde ich vermeiden.


----------



## Saxony (2. Feb 2010)

Hiho,

ich habe nur einen Thread welcher diese Methode benutzt. Wie es aussah passierte das nur wenn ein neues Objekt mit einem schon in der Datenbank befindlichen Objekt übereinstimmte (equals). Da ich aber zu meinen Objekten noch einen Zeitstempel hinzufügen musste, hat sich das Problem auf einmal in Luft aufgelöst. 

@byte
Naja wenn ich den schließe - wie kann ich den wieder öffnen? Es gibt zwar close() aber danach lässt er sich nicht wieder öffnen!? Ich schließe den EM erst bei Beendigung meiner Anwendung.

bye Saxony


----------



## byte (2. Feb 2010)

Saxony hat gesagt.:


> @byte
> Naja wenn ich den schließe - wie kann ich den wieder öffnen? Es gibt zwar close() aber danach lässt er sich nicht wieder öffnen!? Ich schließe den EM erst bei Beendigung meiner Anwendung.



Davon würde ich wirklich abraten! Der EntityManager sollte nur solange offen gehalten werden wie nötig. Du kannst Dir jederzeit einen neuen EntityManager über die EntityManagerFactory erzeugen.

Siehe dazu die Doku:


> A EntityManagerFactory is an expensive-to-create, threadsafe object intended to be shared by all application threads. It is created once, usually on application startup.
> 
> An EntityManager is an inexpensive, non-threadsafe object t*hat should be used once, for a single business process, a single unit of work, and then discarded*.



Lies dazu mal Abschnitt 4.1.1ff: Hibernate EntityManager


----------



## Saxony (2. Feb 2010)

Ah ok,

ich erzeuge nun immer neue EMs aus der einmal erzeugten EMF. Schließe nun auch jeden EM und ganz am Schluss beim Beenden der Anwendung schließe ich dann die EMF.

bye Saxony


----------

