【问题标题】:Transactional and Stream in SpringSpring 中的事务和流
【发布时间】:2019-01-26 02:28:08
【问题描述】:

我试图理解为什么这段代码不起作用

在组件中:

@PostConstruct
public void runAtStart(){

    testStream();
}

@Transactional(readOnly = true)
public void testStream(){
    try(Stream<Person> top10ByFirstName = personRepository.findTop10ByFirstName("Tom")){
        top10ByFirstName.forEach(System.out::println);
    }
}

和存储库:

public interface PersonRepository extends JpaRepository<Person, Long> {
    Stream<Person> findTop10ByFirstName(String firstName);
}

我明白了:

org.springframework.dao.InvalidDataAccessApiUsageException:您正在尝试执行流式查询方法,而无需围绕事务保持连接打开,以便可以实际使用 Stream。确保使用流的代码使用@Transactional 或任何其他声明(只读)事务的方式。

【问题讨论】:

  • @Transactional 需要 Spring AOP。默认的 Spring AOP 实现使用标准的 JDK 代理,它不适用于类内调用。这在official documentation 中有非常详细的说明。如果您需要在同一个类中使用 AOP 语义,请考虑使用 AspectJ 代理。

标签: spring java-8


【解决方案1】:

关于 Spring 的一个关键是,许多带注释的特性使用代理来提供注释功能。即@Transactional@Cacheable@Async 都依赖于 Spring 检测这些注释并将这些 bean 包装在代理 bean 中。

在这种情况下,代理方法只能在类而不是从类中调用时使用。有关该主题,请参阅this

试试:

  1. 重构并从上下文中的另一个类调用此 @Transactional 方法,或者
  2. 通过 self-autowiring 类进入自身并以这种方式调用 @Transactional 方法。

演示(1)

public class MyOtherClass {

    @Autowired
    private MyTestStreamClass myTestStreamClass;

    @PostConstruct
    public void runAtStart(){
        // This will invoke the proxied interceptors for `@Transactional`
        myTestStreamClass.testStream();
    }

}

演示(2)

@Component
public class MyTestStreamClass {

   @Autowired
   private MyTestStreamClass myTestStreamClass;

   @PostConstruct
   public void runAtStart(){
       // This will invoke the proxied interceptors for `@Transactional` since it's self-autowired
       myTestStreamClass.testStream();
   }

   @Transactional(readOnly = true)
   public void testStream(){
       try(Stream<Person> top10ByFirstName = personRepository.findTop10ByFirstName("Tom")){
               top10ByFirstName.forEach(System.out::println);
           }
   }
}

【讨论】:

  • 没有其他干净的想法吗? :P //这个工作。我尝试使用@manith 提到的((RunAtStart)AopContext.currentProxy()).testStream();,但这给了我:` init 方法的调用失败;嵌套异常是 java.lang.IllegalStateException:找不到当前代理:建议将“exposeProxy”属性设置为“真”以使其可用。`
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 2011-06-13
  • 2013-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-19
相关资源
最近更新 更多