wie umgehen mit Ressource EntityManager und E-M-Factory

dermoritz

Bekanntes Mitglied
Ich hab in meinem Projekt einige Entity-Klassen diese werden über eine "normale" Klasse ("dbApi") an den Rest des Projekts angebunden. Nun Frage ich mich wie ich in dieser normalen Klasse mit Entity Manager und der Entity-Manager-Factory umgehen soll.
Eigentlich reichen ja statische ("singleton") Attribute, also jeweils eine Instanz für alle Instanzen der "dbApi", oder? Oder mach ich mir da zu viele Gedanken und es gibt da eine "best practice"?

Nicht nur beim instanziieren bin ich mir unsicher sondern auch beim Freigeben (das verunsichert mich schon immer bei Java). Nach allem was ich weiß sollte man immer eine close()-Methode bereitstellen falls man intern irgendwelche Resourcen hält. In meinem Fall würde diese close-Methode sowolh die EM-Factory als auch den EM freigeben. Nur finde ih es irgendwie blöd dem Konsumenten der Klasse die Verantwortung über die Resourcenfreigabe zu geben - aber da gibts in Java keine richtige Alternative oder?

Um dem aus dem Weg zu gehen: wie schlimm wäre es immer nur lokale EM und EMF zu erzeugen - also in den Methoden, die sie benötigen, dann würden die Methoden am Ende auch die Resourcen freigeben, aber ist es ok eventuell "soviele" em und emf's zu erzeugen?

Edit: Achso ähnliche Fragen hätte ich auch für die EntityTransaction.

Edit: wie so oft gibts durch googeln manchmal mehr Fragen: wo ist der Unterschied zwischen:
Code:
public class Entity

 @PersistenceContext(uniitName="PU")
 private EntityManager em;

und

Code:
public class Entity
...
 emf = Persistence.createEntityManagerFactory("PU");
 em = emf.createEntityManager();
...

und

public class Entity
...
@PersistenceUnit(unitName="PU")
emf = Persistence.createEntityManagerFactory("PU");
em = emf.createEntityManager();
...
[/code]
insbesondere der Unterschied der letzten beiden würde mich interessieren.
?
 
Zuletzt bearbeitet:
G

Gelöschtes Mitglied 5909

Gast
Variante 1 ist Container Managed (Spring, EJB, ...)
Variante 2 ist Application Managed

(dazu sollte dir google genügend infos liefern)

Prinzipiell sollte nix von dem EntityManager usw in der Anwendungslogik verbacken sein, d.h. Man sollte da eine Schicht ausenrum bauen. (Stichwort DAOs)
 

dermoritz

Bekanntes Mitglied
In meinem Falle baue ich aber keine jee Anwendung ich habe also keinen Container der sich drum kümmern kann oder? Bzw. Google hilft in soweit, dass man herausbekommt was container- und application-managed ist, man findet aber nie Beispiele zu Application-managed oder nur solche mit "@PersistenceUnit".
Wo ist der Unterschied zwischen "@PersistenceUnit" und ohne diese Annotation?
 
G

Gelöschtes Mitglied 5909

Gast

dermoritz

Bekanntes Mitglied
danke für die links! endlich mal links die sich explizit mit application managed befassen - irgendwie gehen die meisten anderen quellen von container managed aus. so nun hab ich das mal gelesen und bin zumindest was den EntityManager angeht etwas schlauer.

Meine zunächst verworfene Idee den EM an die Methode zu binden schein gar nicht die schlechteste zu sein. Was ich aber nicht verstehe wieso ich mit der em-Factory nicht genauso verfahren kann. Die Alternative ist ja eine globale EMF zu basteln - nur weiß ich nicht wie ich sicherstellen kann dass der immer geschlossen wird. Eine close methode bereitstellen ist meiner Meinung Verschiebung des Problems.
 
Zuletzt bearbeitet:
G

Gelöschtes Mitglied 5909

Gast
Du kannst die EMF auch in der Methode erzeugen, aber ich Rate davon stark ab.
Die EMF zu erzeugen ist das "teure", den EM zu erzeugen ist nicht teuer.
Sprich beim erzeugen der EMF wird die persistence.xml gescannt, die orm.xml, die Annotationen, L2 Cache, ...

(steht aber auch in den Links drinnen)

Die Alternative ist ja eine globale EMF zu basteln - nur weiß ich nicht wie ich sicherstellen kann dass der immer geschlossen wird. Eine close methode bereitstellen ist meiner Meinung Verschiebung des Problems.

Steht im ersten link. Irgendwann wird deine normale java Anwendung fertig sein, dann rufst du das close auf. In ner webapp kannst du dafür einen Listener nehmen
 

dermoritz

Bekanntes Mitglied
Danke, dann bleibt also tatsächlich nur die Möglichkeit eine close() zu implementieren und das in jeder Klasse, die diese Klasse benutzt. Dann bleibt nur noch zu hoffen, dass der der die GUI bastelt daran denkt es aufzurufen.

Was passiert eigentlich wenn EMF nicht geschlossen wird? Die DB-Verbindung hat ja ein serverseitiges Timeout, gibt es noch andere Probleme?
 

dermoritz

Bekanntes Mitglied
was haltet ihr von meiner Applikations-EMF (alle Objekte die eine emf benötigen nehmen diesen Singleton):

Java:
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class LokaleEntityManagerFactory {
	private static EntityManagerFactory emf = null;
	
	private LokaleEntityManagerFactory(){
		emf = Persistence.createEntityManagerFactory("para14_DB-Schnittstelle_PU");
	}
	
	public static EntityManagerFactory gibEMF(){
		if(emf==null || !emf.isOpen()){
			new LokaleEntityManagerFactory();
		} 
		return emf;
	}
	
	public void close(){
		emf.close();
	}
}
(Mir kommt die Implementierung noch etwas komisch vor - für Singleton, tips?)
In diesem Fall dürfte aber nur die Applikation selbst - beim schließen- das close() aufrufen, oder? Und damit der Garbage-Collector diese Klasse nicht ausversehen "nullt", sollte die Applikation auch ein solches Objekt halten, oder? Alternativ könnte ich auch alle Konsumenten der emf in dieser Klasse registrieren und die würden denn sich dann mit ihrem close() austragen können. Falls sich der letzte ausgetragen hat würde das close() der emf selbst aufgerufen werden. -- gute Idee?
 
Zuletzt bearbeitet:
G

Gelöschtes Mitglied 5909

Gast
wieso machst du so ein schmu mit dem Konstruktor?

Java:
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
 
public class ApplicationEntityManagerFactory {

    private static EntityManagerFactory factory = null;
    
    private ApplicationEntityManagerFactory() {
    	// never called
    }
       
    public static synchronized EntityManagerFactory getEntityManagerFactory() {
        if(factory==null || !factory.isOpen()) {
            ApplicationEntityManagerFactory.factory = Persistence.createEntityManagerFactory("para14_DB-Schnittstelle_PU");
        } 
        return factory;
    }
    
    public static synchronized void close() {
        factory.close();
    }
    
}

Und damit der Garbage-Collector diese Klasse nicht ausversehen "nullt", sollte die Applikation auch ein solches Objekt halten, oder?

Du machst dir zu viele gedanken.. sobal du einmal getEMF aufrufst ist die referenz da. keiner kann sie nullen und sie ist static. dann kann der gc auch nix aufräumen was in dem fall sinn macht.

Falls sich der letzte ausgetragen hat würde das close() der emf selbst aufgerufen werden. -- gute Idee?

da kannst du auch gleich close aufrufen wenn die sich wieder deregistrieren müssen...

Aber wenn du nicht weißt wann, wer der letzte ist kannst du es so machen wenn dir nix anderes einfällt (normalerweise sollte das anders gehn). Aber statt ner referenz auf den konsumenten kannst du auch einfach nur einen counter nehmen

//EDIT weder meins noch deins ist ein singleton btw. das ist auch net nötig da du ja prüfen musst ob die EMF valide ist
 
Zuletzt bearbeitet von einem Moderator:

dermoritz

Bekanntes Mitglied
Danke - ich wusste irgendwas ist komisch mit meinem Konstrukt. Was "singleton" betrifft - das einzige was für mich relevant ist, ist das es nur eine emf instanz zu einem Zeitpunkt gibt. Und das sollte doch in meinem Code so sein? Ich weiß nur nicht so recht ob und wieviele geschlossene EMF es geben kann, deshalb hab ich dass so bei mir gemacht -- die alte emf wird mit "new LokaleEntityManagerFactory();" überschrieben. Damit sollte es auch nie geschlossene EMF's geben?!

Was ich mit meinem blabla üer den Garbage-Collector eigentlich sagen wollte: Prinzipiell ist es nun möglich das eine Klasse einen EMF nimmt, dann wird diese Klasse nicht mehr benötigt und wird weggeschnissen und damit eben auch die emf (falls die Klasse kein close aufruft ist wird die emf trotzdem weggeschmissen oder?)
Dann kommt die nächste Klasse und macht das selbe. Wenns dumm läuft hab ich das was ich eigentlich verhindern wollte: Es werden ständig emf angelegt und wieder weggeschmissen.
Die einzige Alternative sehe ich darin das ganze an die main-Methode zu binden und auch nur diese macht am Ende (hoffentlich) ein close?
 
G

Gelöschtes Mitglied 5909

Gast
Was ich mit meinem blabla üer den Garbage-Collector eigentlich sagen wollte: Prinzipiell ist es nun möglich das eine Klasse einen EMF nimmt, dann wird diese Klasse nicht mehr benötigt und wird weggeschnissen und damit eben auch die emf (falls die Klasse kein close aufruft ist wird die emf trotzdem weggeschmissen oder?)
Nein.

Java:
class foo {
   private fooEMF = LEMF.getEMF();
}

Du meinst wohl sowas. Du denkst wenn das foo objekt gc'd wird, dann ist die EMF weg. Das stimmt aber nicht.
Die Referenz fooEmf zeigt auf die gleiche EMF wie LEMF.emf. Es sind also zwei referenzen auf das gleiche objekt.
Wenn die referenz fooEmf jetzt wegfällt ist die LEMF.emf immernoch da
 

dermoritz

Bekanntes Mitglied
So richtig verstanden hab ich dich nicht, aber ich hatte befürchtet, dass wenn alle Klassen die eine emf halten GC'd werden die EMF auch gc'd wird - so würde das ja mit normalen Klassen passieren. Es wird GC'd was keine Referenz mehr hat, oder?

Die Frage ist: ist die EMF anders? Ist das selbst ein singleton der irgendwie an den Thread oder so gebunden ist?
Ich verstehe diese Klasse nicht wirklich. Hab aber z.B. bemerkt, dass falls man das close() vergisst und die Anwendung beendet wird die DB-Verbindung trotzdem geschlossen. Erööfnet wird die Verbindung z.b. erst mit dem Anfordern eines EM?!

Letzendlich frag ich mich wie schlimm es wäre wenn alle Klassen die es brauche sich eine emf selbst holen. diese Klassen müssen dann zwar alle ein close() haben, aber wie schlimm wäre es wenn es nicht aufgerufen würde?
Oder wie schlimm wäre es lokal in der Methode sowohl emf als auch em zu holen?
 

Ähnliche Java Themen

Neue Themen


Oben