【问题标题】:@Transactional only on one method@Transactional 仅在一种方法上
【发布时间】:2021-04-15 10:01:25
【问题描述】:

我需要创建一个 @Scheduled 方法,它有一个模式列表,并且对于每个模式,从 2 个表中删除行。

    @Scheduled(fixedDelay = 10000)
public void scheduleFixedDelayTask() {
    List<String> presentSchemas = getPresentSchemas();
    for (String schema : presentSchemas) {
        deleteFromCustomerTables(schema);
    }
}

我已将 deleteFromCustomerTables 定义为 @Transactional(propagation = Propagation.REQUIRES_NEW) 并在其中使用 EntityManager 从 2 个表中删除行。

为了使其工作,我需要将@Transactional 添加到 scheduleFixedDelayTask,否则我会收到 TransactionRequiredException。

我的问题是我不希望整个调度程序都成为@Transactional,如果一个模式出现问题,我不想回滚所有模式。

我也尝试过不使用 @Transactional 和使用 :

    Session session = entityManager.unwrap(Session.class);
    Transaction t = session.beginTransaction();
    //exec delete
    t.commit();
    session.close();

但我仍然收到 TransactionRequiredException。 你有解决办法吗?

【问题讨论】:

  • 如果您不想回滚所有更改,那么您可以将事务代码放在 try-catch 块中,出错的代码将失败,循环将尝试其他代码,直到列表结束。
  • 即使我将 scheduleFixedDelayTask 定义为 @Transactional 并将 try-catch 放在 deleteFromCustomerTables(schema) 周围,它仍然会回滚并出现错误“事务静默回滚,因为它已被标记为仅回滚”

标签: java spring spring-boot transactions spring-transactions


【解决方案1】:
  • 您必须确保已配置事务管理器,如下所示:
@Configuration
@EnableTransactionManagement
public class TransactionConfig {

  @Bean
  @Primary
  public PlatformTransactionManager transactionManager() {
    return new JpaTransactionManager();
  }
}
  • 您必须确保方法 deleteFromCustomerTables 不在同一个组件中,如下所示:
@Component
class Component1 {
   void scheduleFixedDelayTask(){...}
}

@Component
class Component2 {
   void deleteFromCustomerTables(){...}
}
 

但是在非常高的层次上,Spring 为类创建代理 在类本身或成员上声明 @Transactional。代理是 在运行时大部分是不可见的。它为Spring注入提供了一种方式 方法调用之前、之后或周围的行为 代理。事务管理只是行为的一个例子 可以上钩。安全检查是另一个。你可以 也为日志记录之类的事情提供你自己的。所以当你注释一个 使用@Transactional 的方法,Spring 动态创建一个代理 实现与您要注释的类相同的接口。和 当客户端调用你的对象时,调用被拦截 以及通过代理机制注入的行为。

【讨论】:

  • 非常感谢!我的问题是使用相同的组件!创建第二个组件解决了这个问题。
猜你喜欢
  • 2011-03-31
  • 1970-01-01
  • 2013-06-25
  • 2018-02-23
  • 2011-09-07
  • 2015-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多