EJB Problem mit Transaktionen

y0dA

Top Contributor
Vorweg wir benutzen JPA mit EJB 3.0 .

Folgende Sachlage:
Wir haben eine Controller-, eine Service- und eine DAOschicht und bisher brauchten wir immer nur 1 Statement - beispielsweise eine Person speichern wird vom "Personencontroller" angestossen, der ruft das Service auf welches wiederum dem DAO sagt "speichere mir das" = 1 Transaktion.
Nun ist es aber so dass bspw. eine Person ein Auto besitzt und selbiges wird nun verkauft und bekommt eine neue Person als Besitzer. Hierfür haben wir wieder einen Controller welcher dann aber , zur Zeit, 2 Services aufrufen muss. Zum einen muss er den alten Personensatz updaten (ein gueltigbis Timestamp setzen) und 2. muss ein anderes Service aufgerufen werden um der neuen Person das Auto umzuhängen.

Beides sollte aber in einer Transaktion laufen und so wie es jetzt ist sind es aber 2 Transaktionen. Sprich eigentlich sollten wir beide Dinge in einem Service abhandeln und hierbei ist das Problem dass wir nicht wissen wie wir hier 1 Transaktion durchführen können. Mit Spring hat das prima mit @Transactional funktioniert, dies bietet EJB aber nicht an.

Hat jemand einen Lösungsvorschlag?

hier die abstrakte dao klasse, selbige wird dann bspw. von Person (PersonDAO) und Auto(AutoDAO) implementiert.

Java:
public abstract class CRUDEntityFacade<T extends XObjekt> implements
		IGenericEntityFacade<T> {
	private static Logger logger;

	protected transient final Class<T> entityClass;

	@PersistenceContext(unitName = "xxx")
	private EntityManager em;

	@SuppressWarnings("unchecked")
	public CRUDEntityFacade() {
		entityClass = (Class) ((java.lang.reflect.ParameterizedType) this
				.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		logger = Logger.getLogger(this.getClass());
	}

	@Override
	public T create(T entity) throws EntityExistsException,
			IllegalStateException, IllegalArgumentException,
			TransactionRequiredException {
		if (logger.isTraceEnabled()) {
			logger.trace("CRUDEntityFacade.create("
					+ entityClass.getSimpleName() + ")");
		}
		em.persist(entity);

		return entity;
	}

	@Override
	public T update(T entity) throws IllegalStateException,
			IllegalArgumentException, TransactionRequiredException {
		if (logger.isTraceEnabled()) {
			logger.trace("CRUDEntityFacade.update("
					+ entityClass.getSimpleName() + ")");
		}
		em.merge(entity);

		if (logger.isDebugEnabled()) {
			logger
					.debug("CRUDEntityFacade.update(Serializable) updated 1 entity: "
							+ entity.toString());
		}
		return entity;
	}
 
Sind genau hierfür nicht die Annotation

javax.ejb.TransactionManagement
und
javax.ejb.TransactionAttribute

da?

Wenn man den DAOs ein TransactionAttribute REQUIRED hinzufügt, und dann beide DAOs aus dem Service heraus aufruft, sollten die afaik in einer Transaktion stattfinden.
 
Sind genau hierfür nicht die Annotation

javax.ejb.TransactionManagement
und
javax.ejb.TransactionAttribute

da?

Wenn man den DAOs ein TransactionAttribute REQUIRED hinzufügt, und dann beide DAOs aus dem Service heraus aufruft, sollten die afaik in einer Transaktion stattfinden.

Fragst du mich jetzt oder meinst du dass das so ist?
 
So halb/halb 😉

Ich habe noch nicht so viel Erfahrung mit EJBs, bin aber der Meinung, dass man die DAOs und Services mit javax.ejb.TransactionAttribute annotieren und den passenden Wert einstellen sollte.
Die Annotation kann man an die Klasse machen und dann zusätzlich noch an abweichende Methoden.

Die Frage in dem Post ging eher in die Richtung, dass das jemand anderes der das hier ließt nochmal bestätigt, nicht das ich Mist verzapfe.

Aber evtl. hilft dir ja schon mal nach javax.ejb.TransactionAttribute zu googlen.
 
Also wie du schon gesagt hast, es funktioniert mit

Java:
@TransactionManagement

hierbei kann man sich dann entscheiden ob das Transaktionsmanagement der Container übernehmen soll oder die Bean. Ich habe mich für die Bean entschieden und das sieht dann so aus:

Java:
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class ServiceA implements ServiceALocal {
	@Resource
	UserTransaction tx;

public void doXXX(ObjektA a,
			ObjektB b) {
		try {
			tx.begin();
			aFacade.update(a);
			bFacade.update(b);
			tx.commit();
		} catch (Exception e) {
			// TODO: handle exception
		}
	}
Mit dieser Variante "erspart man sich
Java:
@TransactionAttribute
selbiges ist nur für den Container notwendig, also wenn der Container das Transaktionsmanagement übernimmt.
 
Hatte ich ja mit meinem Halbwissen tatsächlich einen Treffer. 😀 Darf ich noch fragen, wieso du Bean Managed Transaktionen nutzt und nicht einfach die (zumindest vermeintlich) bequemeren Container Managed Transaktionen?
 
Hatte ich ja mit meinem Halbwissen tatsächlich einen Treffer. 😀 Darf ich noch fragen, wieso du Bean Managed Transaktionen nutzt und nicht einfach die (zumindest vermeintlich) bequemeren Container Managed Transaktionen?

Ja weil ich mit dem Containerzeug die @TransactionAttribute Annotation in die DAO Klassen setzen müsste und ich vllt. eine dieser DAOs auch noch woanders aufrufen möchte ohne dass selbige dann sich in eine laufende Transaktion hängt.
 

Neue Themen


Zurück
Oben