簡體   English   中英

已經在ejb內時打開新交易

[英]Open new transaction when already inside ejb

請考慮以下情況:

@Stateless
@Clustered
public class FacadeBean implements Facade {

    @EJB
    private Facade facade;

    @Override
    public void foo(List<Integer> ids) {
        // read specific id's from the db
        for (Integer id : ids) {
            facade.bar(id);
        }
    }

    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void bar(Integer id) {
        // save something to the db
    }

}

從ejb外部調用方法foo。 我希望每個id在自己的事務中執行,以便數據直接保存到數據庫中。 此類之外的foreach是不可能的。 我想知道什么是最好的方法嗎? 此刻,我再次注入接口,以跨過ejb邊界(以便對TransactionAttribute進行評估)。

您關於循環參考的方法非常好。 允許在EJB中進行循環引用。 為了開始新的事務或@Asynchronous線程,這甚至是必需的(否則,當前線程仍會阻塞)。

@Stateless
public class SomeService {

    @EJB
    private SomeService self; // Self-reference is perfectly fine.


    // Below example starts a new transaction for each item.

    public void foo(Iterable<Long> ids) {
        for (Long id : ids) {
            self.fooInNewTransaction(id);
        }
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void fooInNewTransaction(Long id) {
        // ...
    }


    // Below example fires an async thread in new transaction.

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void bar(Iterable<Long> ids) {
        for (Long id : ids) {
            self.fooAsynchronously(id);
        }
    }

    @Asynchronous
    public void fooAsynchronously(Long id) {
        // ...
    }

}

僅在較舊的容器中,此方法不起作用,最顯着的是帶有古老EJB 3.0 API的JBoss AS 5。 這就是為什么人們發明了諸如SessionContext#getBusinessObject()類的變通方法,甚至是通過JNDI手動抓取的原因。

這些天這些都是不必要的。 這些是解決方法,而不是解決方案。

我個人只會以相反的方式進行交易。 顯然, foo()方法從不打算進行事務處理。

@Stateless
public class SomeService {

    @EJB
    private SomeService self;

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public void foo(Iterable<Long> ids) {
        for (Long id : ids) {
            self.foo(id);
        }
    }

    public void foo(Long id) {
        // ...
    }

}

根據具體的功能要求,您甚至可以使foo(Long id) @Asynchronous ,從而加快任務的執行速度。

您真的必須在一個類中同時使用這兩種方法嗎? 您可以將bar()移到自己的bean上並使其具有事務性。 然后,您不必使用這種自我注入。

您也可以嘗試使用SessionContext#getBusinessObject()方法。

@Resource
SessionContext sessionContext;

@Override
public void foo(List<Integer> ids) {
    Facade facade = sessionContext.getBusinessObject(Facade.class);
    // read specific id's from the db
    for (Integer id : ids) {
        facade.bar(id);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM