-->

Why does not commit transaction of Requires_New?

2019-05-23 01:23发布

问题:

I have a problem. I am working on java application server(sap netweaver) with I am using ejb 3.0

So I want to database insert one by one. Because I have too much data and i have to divide data. So I made try test code and it did work but it did not work as I want.

I want to create a new transaction for each part and of course at the end method(transaction) should be commit.

Sample code is below;

package com.transaction.jobs;

import javax.ejb.Local;

/**
 *
 * @author muratdemir
 */
@Local
public interface TestTransactionLocal {

    public void onStart();

    public void insertObject(int i);
}

and

package com.transaction.jobs;

import com.transaction.service.DatabaseServiceLocal;
import com.transaction.entity.Item;
import com.transaction.entity.Logger;
import java.util.Date;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.EJBContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;

/**
 *
 * @author muratdemir
 */
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class TestTransactionService implements TestTransactionLocal {

    @EJB
    DatabaseServiceLocal databaseService;

    @Resource
    EJBContext context;

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void onStart() {
        try {
            System.out.println("START");

            Logger log1 = new Logger(new Date(), ">>>T1 commiting");
            databaseService.create(log1);

            System.out.println(">>>T1 committing");

            Thread.sleep(5000);

            for (int i = 1; i < 10; i++) {
                System.out.println("Call new Transaction");

                insertObject(i);

                Thread.sleep(2000);
            }

            Thread.sleep(5000);

            Logger log2 = new Logger(new Date(), "<<<T1 commiting");

            databaseService.create(log2);

            System.out.println("<<<T1 committing");

            Thread.sleep(5000);
            System.out.println("END");
        } catch (Exception e) {
            e.printStackTrace();
            context.setRollbackOnly();
        }

    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void insertObject(int i) {
        try {
            System.out.println("New Transaction Start i:" + i);

            Item item = new Item(new Date(), "Name_" + i);

            databaseService.create(item);

            System.out.println("commit transaction: " + i);
        } catch (Exception e) {
            e.printStackTrace();
            context.setRollbackOnly();
        }
    }

}

The insertObject(Requires_New) function is work but it did not commit. It waiting for commit other onStart(REQUIRED) function. If mytimer function is end, the insert function makes all commit.

Why new transaction is did not committed?

Note: If I change transaction attribute of the onStart function REQUIRED to NOT_SUPPORTED it works as I want. Why it works this way?

回答1:

You have to initialize another TestTransactionLocal with a use of SessionContext#getBusinessObject method. This way your TestTransactionLocal instance will respect @TransactionAttribute annotation.

@Resource
private SessionContext sessionContext;

private TestTransactionLocal local;

@PostConstruct
void init() {
    local = sessionContext.getBusinessObject(TestTransactionLocal.class);
}

Then invoke insertObject() through this new reference:

local.insertObject(i);

See this blog post: http://www.adam-bien.com/roller/abien/entry/how_to_self_invoke_ejb



回答2:

You're calling prepare() method directly, so the transaction annotation isn't considered. You would need to call it through its own interface i.e. myTestTimerLocal.prepare(), for any transactional effect.