0

I'm facing a huge problem when I'm trying to use multiple datasources on spring-boot. My problem is because I'm using spring batch and I don't have enough privilegies to create the METADATA tables from spring-batch on my production database so I need to use for example a H2 to create these tables, but when I'm trying to load in my model a field with a relationship as @OneToMany in my job processor I'm receiving a LazyInitializationException

spring-boot version 2.3.4.RELEASE

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

My processor

   @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;
    }
 }

Error:

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

I created the batch datasource as the primary

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

1 Answer 1

1

Lazy Initialisation happend when you manipulate a field with @OneToMany outside a transaction.

Opening a transaction

For starting a transaction you will have different method

  1. Using @Transactional on the public method of your Service method's (process for your case)
  2. Use TransactionTemplate to open a transaction

MultiDataSource and TransactionManager

When your are in a MonoDatasource project this should be enough but in a MultiDatasource you will have to be careful from which datasource the data come from. And in fonction of that you will have to use the corresponding transsactionManager.

For that you can add the property transactionManager=myTransactionManagerForDatasourceA in @Transactional annotation.

If you don't have (Or don't know is name) a transactionManager you will have to define it

Define a primary transactionManager

If you don't want to use transactionManager value in all @Transactional annotations because in 99% of your case you will use the same Datasource you can annote your dataSource bean method with @Primary. By default @Transactional will use the primary transactionManager and if you have to you can use transactionManager annotation value to use the other transactionManager

Sign up to request clarification or add additional context in comments.

1 Comment

Adding the transactionManager property to the annotation worked for me. However, the way I implemented two datasources it's suppose to exclude certain repositories from being wired with the primary transaction manager and yet that doesn't seem to be the case :/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.