简体   繁体   中英

Java EE: Eclipselink transaction missing

I have a maven based Java EE project that should run on GlassFish v3. There is a JSF ManagedBean that injects an EJB service. ManagedBean calls one of the injected EJB's method on button click where some JPA operation happens (creation of new entity object, persisting, flushing). When the EntityManager.flush() called then it throws an exception:

Caused by: javax.persistence.TransactionRequiredException:  Exception
Description: No transaction is currently active

The data source is a jta data source with JTA transaction type (defined in persistence.xml).

I've already found a solution, but it is not satisfying due to deployment issues. If I put the next line of code into the persistence.xml then it runs without any problem:

<property name="eclipselink.target-server" value="SunAS9"/>

Because of this reason, I assume that it is a deployment problem, when the eclipselink does not recognize the JTA manager.

Any suggestions would be appreciated, thank You!

UPDATE:

@MRalwasser: here is the full stack trace. (sorry, i had to remove the real package names, it is masked.package.name now) stack trace on pastebin

@Chris: sorry i forgot to mention, that the GeneriDao class creates the entity manager via the factory method, NOT by dependency injection.

Only EJB can working in CMT by default. In Managed beans or CDI beans you have to implement your own mechanism for handling transactions and run your service from within it.

public class ManagedBean {        

    @Inject
    yourEjbService service;

    @Resource
    UserTransaction utx;

    public void save(){
        try{
            utx.begin();
            service.doAction();
            utx.commit();
        } catch (Exception e) {
            try {
                utx.rollback();
            } catch (Exception ex) {
                ...
            } 
        }
    }
    ...
 }

You also don't have to call EntityManager.flush() neither in your EJB nor in managed bean if you are injecting EntityManager using @PersistenceContext . It will detach entities automatically after each method in your EJB ends.

The persistence control mechanisms of Java Enterprise have several options and specific design choices. In almost any Java EE implementation I worked with, comtainer managed transactions (CMT) were used. In an occastional situation, bean managed transactions (BMT) can be the choice.

Bean managed transactions can be preferred when you need to be sure, exactly when the 'commit' (or 'rollback') takes place during program execution. This can be required in a high-performing time-critical application area. For an example of BMT, see eg the section 'Bean Managed Transactions' in examples, Bean Managed Transactions

Container managed transactions means that the software in the application server ( 'the container') calls a 'begin' transction before Java code is executed that makes use of a persistence context. When the code execution is finisned (when the call tree has returned, eg as a result of a web-request), the application server calls 'commit'. Consequently, the modified entities are actually updated in the application database.

In Java EE, the statements: @TransactionManagement(TransactionManagementType.CONTAINER) and @TransactionManagement(TransactionManagementType.BEAN) indicate container managed transactions, or bean managed transactions, respectively. Java EE defines several types of beans: session-driven bean, message-driven bean, local bean. These beans are generally @Stateless , and can all work with container managed transactions.

Detailed control of container managed transaction handling can in EE be specified by adding the annotations:

@TransactionAttribute(REQUIRES_NEW) 
public void myTopLevelMethodWhichStartsNewInnerTransaction()
....
@TransactionAttribute(REQUIRED)
public void myTopLevelMethodContinueExistingTransactionIfAny()
....
@TransactionAttribute(NEVER)
public void myNoCurrentTransactionAllowedWhenMethodCalled()
....

Flush

The necessarity of calling 'flush' to ensure that the database cache is written on disk, depends on the type of database used. Eg for Postgress calling flush makes a difference, whereas for the in-memory database 'derby', flush has no effect, and can in that latter situation cause an error similar to the one reported in this question. The effect of flush is thus database dependent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM