2011-02-24 127 views
18

在Spring中,如果沒有一個交易方法,則使用@Transactional註解的方法將獲得一個新的交易,但我注意到交易方法沒有獲得任何交易如果它是從一個非事務性的調用的事務。這是代碼。@從另一種方法調用的交易方法不會獲得交易

@Component 
public class FooDao { 
    private EntityManager entityManager; 

    @PersistenceContext 
    protected void setEntityManager(EntityManager entityManager) { 
     this.entityManager = entityManager; 
    } 

    @Transactional 
    public Object save(Object bean) { 
     return this.entityManager.merge(bean); 
    } 

    public Object saveWrap(Object bean) { 
     return save(bean); 
    } 
} 

@Component 
public class FooService { 
    private FooDao fooDao; 

    public void save(Object bean) { 
     this.fooDao.saveWrap(bean); // doesn't work. 
     this.fooDao.save(bean); // works 
    } 
} 

saveWrap()是調用save()這是事務性的,但saveWrap()不會存留任何改變一個普通的方法。

我正在使用Spring 3和Hibernate 3.我在這裏做錯了什麼?謝謝。

回答

30

這是Springs AOP的侷限性之一。由於dao bean實際上是一個由Spring創建的代理,這意味着從同一個類中調用方法不會調用advice(這是事務)。其他切入點也是如此

+2

用@Transactional註釋saveWrap方法沒有什麼壞處。事務傳播的默認行爲是REQUIRED,這意味着如果您要獲得嵌套事務(即,您處於事務中,然後調用另一個也是@Transactional的方法),則只需使用現有事務,而不是創建另一個如果這就是你害怕的) – 2011-02-24 19:38:12

+0

如何使用cglib來代理?我記得cglib代理的建議,即使你在同一個類中調用它。 – hiway 2018-01-29 04:08:28

11

是的,這是預期的行爲。 @Transactional告訴spring在對象周圍創建一個代理。代理攔截從其他對象調用對象。代理不會攔截對象內的調用。

如果你想做這個工作,在從「外部」調用的方法上添加@Transactional

+1

另一種選擇是將整個類標記爲事務性的,方法是在類的頂部放置@Transactional()(有可能是readOnly = true/false,propagation = something等),然後重寫readOnly和/根據需要的每個方法的值。 – esaj 2011-02-24 19:31:14

2

我知道這有點晚,但只是想增加一種方法來克服這個限制,就是在方法中從應用程序上下文中獲取spring bean並調用方法。當從應用程序上下文獲得spring bean時,它將是代理bean而不是原始bean。由於代理bean現在正在調用該方法而不是原始bean,交易建議將在其上實施。