微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如果消息处理程序 (Consumer<T>) 调用用 @Transactional 注释的服务,则没有可用/创建事务

如何解决如果消息处理程序 (Consumer<T>) 调用用 @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 方法持久化实体并尝试获取延迟加载的关系:

@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 上获得。

最初的问题发生在具有更复杂设置和依赖关系的更大项目中。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?