如果消息处理程序 (Consumer<T>) 调用使用 @Transactional 注释的服务,则没有事务是 available/created
No transaction is available/created if a message handler (Consumer<T>) calls a service annotated with @Transactional
该应用程序是一个 Spring 启动应用程序,带有 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()
访问延迟加载的实体抛出 org.hibernate.LazyInitializationException: could not initialize proxy - no Session
。因此 Service
未被代理,并且 process
方法中没有可用的事务(和会话)。一些调试验证了这个假设。
但是,如果从 rest 控制器调用 process
方法,事务可用并且代码工作正常。
此外,消息处理程序中 process
方法的调用可以包装到 TransactionTemplate
中,这修复了缺少事务的问题:
@Bean
public Consumer<Person> consume(Service service, TransactionTemplate transactionTemplate) {
return person -> transactionTemplate.execute(() -> service.process(person));
}
如果从消息处理程序调用该服务,为什么不代理该服务? Spring Cloud Stream 是否与声明式事务管理集成?
好的,我解决了。
我创建了一个简单的项目来测试用例,它按预期工作。该代码可在 GitHub.
上获得
最初的问题发生在一个更大的项目中,具有更复杂的设置和依赖关系。
该应用程序是一个 Spring 启动应用程序,带有 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()
访问延迟加载的实体抛出 org.hibernate.LazyInitializationException: could not initialize proxy - no Session
。因此 Service
未被代理,并且 process
方法中没有可用的事务(和会话)。一些调试验证了这个假设。
但是,如果从 rest 控制器调用 process
方法,事务可用并且代码工作正常。
此外,消息处理程序中 process
方法的调用可以包装到 TransactionTemplate
中,这修复了缺少事务的问题:
@Bean
public Consumer<Person> consume(Service service, TransactionTemplate transactionTemplate) {
return person -> transactionTemplate.execute(() -> service.process(person));
}
如果从消息处理程序调用该服务,为什么不代理该服务? Spring Cloud Stream 是否与声明式事务管理集成?
好的,我解决了。
我创建了一个简单的项目来测试用例,它按预期工作。该代码可在 GitHub.
上获得最初的问题发生在一个更大的项目中,具有更复杂的设置和依赖关系。