spring-boot - 如果消息处理程序(消费者) 调用使用@Transactional 注释的服务
问题描述
该应用程序是一个 Spring Boot 应用程序,其中包含使用函数式编程模型定义的 Spring Data JPA 和 Spring Cloud Stream (RabbitMQ)。
功能消息处理程序调用服务:
@Configuration
class MessageHandlerConfiguration {
@Bean
public Consumer<Person> consume(Service service) {
return person -> service.process(person);
}
}
服务方法持久化实体并尝试获取延迟加载的关系:
@Service
class Service {
//constructor injection
private PersonRepo personRepo;
@Transactional
public void process(Person person) {
// create personEntity
// ...
var personEntity = personRepo.save(personEntity);
// throws org.hibernate.LazyInitializationException
var addressEntity = personEntity.getAddress();
}
}
personEntity.getAddress()
通过throws访问延迟加载的实体org.hibernate.LazyInitializationException: could not initialize proxy - no Session
。因此,Service
没有代理,并且该process
方法中没有可用的事务(和会话)。一些调试验证了这个假设。
但是,如果process
从休息控制器调用该方法,则事务可用并且代码可以正常工作。
此外,process
可以将消息处理程序中的方法调用包装到 中TransactionTemplate
,这解决了丢失事务的问题:
@Bean
public Consumer<Person> consume(Service service, TransactionTemplate transactionTemplate) {
return person -> transactionTemplate.execute(() -> service.process(person));
}
如果从消息处理程序调用,为什么不代理服务?Spring Cloud Stream 是否与声明式事务管理集成?
解决方案
推荐阅读
- html - 如何从多个样式表中选择特定的 CSS 选择器
- reactjs - fireEvent.change() 不输入值
- laravel - 使用 laravel vue rest api 获取用户权限
- qooxdoo - selenium:如何知道 qooxdoo 按钮是否启用
- php - 为什么当我启动本地服务器时 Symfony 会询问有效的令牌?
- css - 使用卡片图像作为滑块 - Bootstrap 4
- rust - 如何在作为子进程运行的 shell 中执行命令?
- javascript - 如何在点击时获取传单 ImageOverlay 的像素坐标
- php - 来自 PDO 查询的 SQL 结果数组具有重复值
- assembly - 内联汇编器和位域访问