'Spring-Data JPA: InvalidDataAccessApiUsageException for @Transactional
I run a Spring Boot Application wiht @EnableTransactionManagement and want to use @Transactional(readOnly = true) for some database queries.
But I receive a confusing error message. I'm using Spring, Spring Boot and and 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)
{
...
}
}
}
When I run my SpringBootApplication I will receive the following log messages / errors:
[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
First JPA opens a transaction and close it immediately with an exception, that I want to execute a streaming query method without a surrounding transaction. Does someone had this before?!
Solution 1:[1]
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;
...
}
So yes, to the comment above, MyDataBean is an entity.
These are the classes after the changes mentioned in the comments above:
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)
{
...
}
}
}
When I start the application I receive the error:
org.springframework.data.mapping.PropertyReferenceException: No property streamAll found for type MyBeanData!
The maven dependencies are:
- org.springframework.boot:spring-boot-starter:1.5.6.RELEASE
- org.springframework.boot:spring-boot-starter-test:1.5.6.RELEASE
- org.springframework.boot:spring-boot-starter-web:1.5.6.RELEASE
- org.springframework.boot:spring-boot-starter-data-jpa:1.5.6.RELEASE
- org.hibernate:hibernate-core:5.0.12.Final
- org.hibernate:hibernate-entitymanager:5.0.12.Final
- org.springframework.data:spring-data-jpa:1.11.6.RELEASE
- ...
- ...
Could this be a dependencies problem? I couldn't find a spring/spring-boot/spring-data dependency matrix...
Solution 2:[2]
I fixed it!
It was a problem with the spring context.
When I initialize MyBeanService, I stored the bean into an HashMap with an corresponding request-object.
dispatcher.put(MyBeanRequest.class, this);
...
((MyAbstractService) dispatcher.get(MyBeanRequest.class).handleRequest(...);
it works, when I search for the bean in the spring context:
dispatcher.put(MyBeanRequest.class, this.getClass());
...
((MyAbstractService) appContext.getBean(dispatcher.get(requestObject.getClass()))).handleRequest(...);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | flo-ferox |
| Solution 2 | flo-ferox |
