Spring-Data JPA:@Transactional的InvalidDataAccessApiUsageException

时间:2018-01-18 13:39:20

标签: java spring hibernate spring-data-jpa transactional

我使用@EnableTransactionManagement运行Spring Boot应用程序,并希望使用@Transactional(readOnly = true)进行一些数据库查询。

但是我收到一条令人困惑的错误消息。 我使用的是Spring,Spring Boot和Spring Data JPA。

MySpringBootApplication.java

@SpringBootApplication
@EnableTransactionManagement
@ComponentScan("com.deutscheboerse.regrephub")
@EntityScan(basePackages = "com.deutscheboerse.regrephub")
@EnableJpaRepositories(basePackages = "com.deutscheboerse.regrephub")
@Slf4j
public class MySpringBootApplication
{
   ... Some @Autowired variables ...

   public static void main(String[] args)
   {
      SpringApplication.run(MySpringBootApplication.class, args);
   }

   ... 
}

MySpringBootApplicationConfiguration.java

@Configuration
@EnableEncryptableProperties
@EnableTransactionManagement
@EnableAsync
@Slf4j
public class MySpringBootApplicationConfiguration
{
   ... Some @Autowired variables ...

   @Bean
   @ConfigurationProperties(prefix = "spring.datasource")
   public DataSource dataSource()
   {
      return DataSourceBuilder
            .create(this.dataSourceProperties.getClassLoader())
            .url(this.dataSourceProperties.getUrl())
            .username(this.dataSourceProperties.getUsername())
            .password(this.dataSourceProperties.getPassword())
            .build();
    }

    ...
}

MyBeanDao.java

@Repository
public interface MyBeanDao extends JpaRepository<MyBeanData, Long>
{
    @QueryHints(value = @QueryHint(name = HINT_FETCH_SIZE, value = "" + Integer.MIN_VALUE))
    @Query(value = "SELECT * FROM MY_TABLE", nativeQuery = true)
    @Transactional(readOnly = true)
    Stream<MyBeanData> streamAll();
}

MyBeanService.java

@Service
@Slf4j
public class MyBeanService extends AbstractService
{
    @Autowired
    public MyBeanService(...)
    {
       ...
    }

    @Override
    @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
    public void handleRequest(Object request, Message msg)
    {
       try (Stream<MyBeanData> data = myBeanDao.streamAll())
       {
          ...
       }
       catch (Exception e)
       {
          ...
       }
    }
}

当我运行SpringBootApplication时,我将收到以下日志消息/错误:

[TransactionInterceptor:474] Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.streamAll]
[TransactionInterceptor:517] Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.streamAll] after exception: org.springframework.dao.InvalidDataAccessApiUsageException: You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses @Transactional or any other way of declaring a (read-only) transaction.
[RuleBasedTransactionAttribute:131] Applying rules to determine whether transaction should rollback on org.springframework.dao.InvalidDataAccessApiUsageException: You're trying to execute a streaming query method without a surrounding transaction that keeps the connection open so that the Stream can actually be consumed. Make sure the code consuming the stream uses @Transactional or any other way of declaring a (read-only) transaction.
[RuleBasedTransactionAttribute:148] Winning rollback rule is: null
[RuleBasedTransactionAttribute:153] No relevant rollback rule found: applying default rules

首先JPA打开一个事务并立即关闭它,但是我想要执行一个没有周围事务的流式查询方法。 有人之前有这个吗?!

2 个答案:

答案 0 :(得分:0)

MyBeanData.java

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@Table(name = "MY_TABLE_NAME")
@Data
@NoArgsConstructor
public class ValLeiPageData
{
    @Id
    private Long id;

    ...
}

是的,对于上面的评论,MyDataBean是一个实体。

这些是上述评论中提到的更改之后的类:

MyBeanDao.java

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
...

@Repository
public interface MyBeanDao extends JpaRepository<MyBeanData, Long>
{
    // removed @Query annotation
    Stream<MyBeanData> streamAll();
}

MyBeanService.java

import org.springframework.stereotype.Service;

@Service
@Slf4j
public class MyBeanService extends AbstractService
{
    @Autowired
    public MyBeanService(...)
    {
       ...
    }

    @Override
    public void handleRequest(Object request, Message msg)
    {
       try (Stream<MyBeanData> data = myBeanDao.streamAll())
       {
          ...
       }
       catch (Exception e)
       {
          ...
       }
    }
}

当我启动应用程序时,我收到错误: org.springframework.data.mapping.PropertyReferenceException: No property streamAll found for type MyBeanData!

maven依赖项是:

  • org.springframework.boot:弹簧引导起动:1.5.6.RELEASE
  • org.springframework.boot:弹簧引导起动试验:1.5.6.RELEASE
  • org.springframework.boot:弹簧引导起动的web:1.5.6.RELEASE
  • org.springframework.boot:弹簧引导起动数据JPA:1.5.6.RELEASE
    • org.hibernate作为:休眠核:5.0.12.Final
    • org.hibernate作为:休眠-的EntityManager:5.0.12.Final
    • org.springframework.data:spring-data-jpa:1.11.6.RELEASE
    • ...
  • ...

这可能是依赖问题吗? 我找不到spring / spring-boot / spring-data依赖矩阵......

答案 1 :(得分:0)

我修好了!

弹簧环境存在问题。

当我初始化MyBeanService时,我将bean存储到带有相应请求对象的HashMap中。

dispatcher.put(MyBeanRequest.class, this);
...
((MyAbstractService) dispatcher.get(MyBeanRequest.class).handleRequest(...);

当我在spring上下文中搜索bean时,它可以工作:

dispatcher.put(MyBeanRequest.class, this.getClass());
...
((MyAbstractService) appContext.getBean(dispatcher.get(requestObject.getClass()))).handleRequest(...);