首页 > 解决方案 > 使用多个数据源的 LazyInitializationException

问题描述

当我尝试在 spring-boot 上使用多个数据源时,我面临着一个巨大的问题。我的问题是因为我使用的是 spring 批处理并且我没有足够的权限来从我的生产数据库上的 spring-batch 创建 METADATA 表所以我需要使用例如 H2 来创建这些表,但是当我尝试在我的工作处理器中加载一个与@OneToMany 关系的字段我收到一个 LazyInitializationException

spring-boot 版本 2.3.4.RELEASE

 @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
 private List<Conta> accounts = new ArrayList<>();

我的处理器

   @Slf4j
    public class AccountItemProcessor implements ItemProcessor<AccountMaster, List<AccountBatch>> {
    @Autowired
    private ContaBatchConfigProperties contaBatchConfigProperties;

    @Override
    public List<AccountBatch> process(AccountMaster accountMaster) throws Exception {
        List<AccountBatch> accountBatchList = new ArrayList<>();
        for (Accounts obj: accountMaster.getAccounts()) {
            accountBatchList.add(ContaBatch.of(obj, contaBatchConfigProperties));
            accountBatchList.add(ContaBatch.of(accountMaster, contaBatchConfigProperties, obj));
        }
        return accountBatchList;
    }
 }

错误:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: br.com.example.AccountMaster.accounts, could not initialize proxy - no Session

我将批处理数据源创建为主

@Bean(name="batchDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.batch.datasource")
public DataSource batchDataSource(){
    return DataSourceBuilder.create().build();
}

标签: spring-bootspring-data-jpaspring-batch

解决方案


@OneToMany当您在事务外部操作字段时会发生延迟初始化。

开启交易

对于开始交易,您将有不同的方法

  1. 在您的 Service 方法的公共方法上使用 @Transactional(您的案例的过程)
  2. 使用 TransactionTemplate 打开一个事务

多数据源和事务管理器

当您在 MonoDatasource 项目中时,这应该足够了,但在 MultiDatasource 中,您必须小心数据来自哪个数据源。为此,您将不得不使用相应的事务管理器。

为此,您可以transactionManager=myTransactionManagerForDatasourceA@Transactional注释中添加属性。

如果您没有(或不知道名称)事务管理器,则必须定义它

定义一个主事务管理器

如果您不想在所有@Transactional注释中使用 transactionManager 值,因为在 99% 的情况下您将使用相同的 Datasource,您可以使用 @Primary 注释您的 dataSource bean 方法。默认情况下,@Transactional 将使用主事务管理器,如果必须,您可以使用事务管理器注释值来使用其他事务管理器


推荐阅读