【问题标题】:Will called function be still in transaction if we have a @Transaction in caller function?如果我们在调用函数中有@Transaction,被调用函数是否仍处于事务中?
【发布时间】:2012-06-25 18:45:07
【问题描述】:

我知道我们需要使@Transactional 边界尽可能短。这是代码:

我正在通过 Spring 依赖注入使用 userDAO 对象:

private static ApplicationContext context ;
private UserDAO userDAO;

public TransactionsTest() {
    userDAO = (UserDAO) context.getBean("userDAO");
} 

我从TransactionsTest 类调用testSaveUserAccounts(),试图使用userDAO 插入/更新数据。

案例一:

@Transactional
public void testSaveUserAccounts() {
    UserAccounts userAccounts = new UserAccounts();
    userAccounts.setCommunityId(10L);
    userDAO.saveObject(userAccounts);
}

// This method is inside UserDAO
        public void saveObject(Object object) {
        entityManager.merge(object);
    }

案例 2:

@Transactional
public void testSaveUserAccounts() {
    UserAccounts userAccounts = new UserAccounts(); 
    userAccounts.setCommunityId(10L);
    userDAO.saveObject(userAccounts);
}

// This method is inside UserDAO
    @Transactional(propagation=Propagation.REQUIRED)
    public void saveObject(Object object) {
        entityManager.merge(object);
    }

弹簧上下文:

    <tx:annotation-driven transaction-manager="transactionManager" />

        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory" />
        </bean>

        <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <property name="dataSource" ref="dataSourceLocal" />
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
            </property>
            <property name="persistenceUnitName" value="spring-jpa" />
      </bean>

用户DAO:

@Repository
public class UserDAO extends BaseDAO {

    @Transactional(propagation=Propagation.REQUIRED)
    public void saveObject(Object object) {
        entityManager.merge(object);
    }

}

BaseDAO:

public abstract class BaseDAO {

    protected EntityManager entityManager;
    protected HashMap<String,Long>  eventIdMap = new HashMap<String,Long>();


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


    public <T> T getById(final Class<T> clazz, final Serializable id) {
        T object = clazz.cast(entityManager.find(clazz, id));
        return object;
    }


    @Transactional
    public Object save(Object ob) {
        Object object = entityManager.merge(ob);
        return object;
    }


    @Transactional
    public void persist(Object ob) {
        entityManager.persist(ob);
    }


    @SuppressWarnings("unchecked")
    public <T>  ArrayList<T> getAll(final Class<T> clazz) {
        String hqlQuery = "from "+ clazz.getSimpleName();
        ArrayList<T> list  = (ArrayList<T>)entityManager.createQuery(hqlQuery).getResultList();
        return list;
    }

}

我一直在围绕几个事务边界进行试验 REQUIREDREQUIRES_NEWSUPPORTS 等,但无法确定为什么案例 1(当调用方法 2 时,它在方法 1 的事务边界内)确实如此不合并数据,而在案例 2 中解决了这个问题。

既然我已经在事务边界内标记了调用函数,为什么还要在内部方法中指定@Transactional?

【问题讨论】:

  • 你没有,它应该可以正常工作。其他问题/不同,也许 method1 不在实际应用 AOP 拦截器的地方?
  • 如果我们在内部方法中插入/更新数据(没有事务边界),它不会提交我的更改,即使在方法 1 完成后也是如此。这可以通过将 @Transactional 放在内部方法定义上来解决。
  • 我认为您需要添加一些真实的代码,您的示例非常简化,您的问题甚至不再存在。
  • @RasmusFranke 如果有帮助,请查看上面的编辑问题摘要。
  • testSaveUserAccounts() 真的在 Spring bean 中吗?如果忽略该方法上的@Transactional,您的问题将是有意义的。我看到@Affe 也暗示了这一点。

标签: java spring transactions


【解决方案1】:

您的事务测试类不是 Spring Bean,这就是案例 1 不起作用的原因。 Spring 需要检测一个方法上有@Transactional,当spring 向spring bean 工厂注册bean 时,它会这样做。

另外请记住,如果您在同一个 bean 中执行基于代理的 AOP 调用,事务方面不会捕获到,除非您使用 AspectJ 加载时间编织或 AspectJ 编译时间编织。

将@Transactional 放在你的 Dao 上也不是一个好主意,因为事务边界最好在服务层标记。原因是特定的服务方法可能需要与多个 Dao 进行交互,并且您希望这些 Dao 的操作成为服务层启动的 tx 的一部分,而不是必须分析 Dao 以查看传播行为是什么。

你能发布测试类的完整代码吗?

【讨论】:

    【解决方案2】:

    @Transactional 在本地不做任何事情,它只有在从不同的服务调用时才有效。换句话说,您必须保留当前上下文,以便事务注释执行任何操作。因此在两种情况下调用方法 1 是相同的,只有在从另一个服务调用方法 2 时,情况 2 才会执行任何操作。

    【讨论】:

      猜你喜欢
      • 2020-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-18
      • 1970-01-01
      • 2016-10-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多