I need to run an asynchronous job that imports data (read from a file) to a MySQL DB. I am using Spring Data's CrudRepository. The problem is that despite calling the save method, no data is persisted to the DB.

Honestly, I do not know how to start solving this issue. I am not seeing any errors or warnings in my logs, and searching on Google I only found the following suggestion:

Spring JPA: Data not saved to Database when processing from an Async method

However, I have already applied it, and my code is still not working. Running the code synchronously (by removing the @Async annotation), everything works as expected.

A snippet of my code:

AsyncImportService.java

@Service
public class AsyncImportService {
    @Autowired
    private ImportService importService;

    @Async
    public void import() {
        importService.import();
    }
}

ImportService.java

@Service
public class ImportService {
    @Autowired
    private AddressCrudRepository addressRepository;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void import() {
        List<Adres> adresses = new ArrayList<>();

        // Open file and create buffered reader using try-with-resources
        try (BufferedReader reader = ...) {
            while((line = reader.readLine()) != null) {
                // mapAddress converts a line of text to an Address object
                addresses.add(mapAddress(line));
            }

            addressRepository.save(adresses);
        } catch (IOException e) {
            // Handle exception
        }
    }
}

AdresCrudRepository.java

public interface AddressCrudRepository extends CrudRepository<Address, Long> {
}

I expect my addresses to be saved to the DB, but after running the job (and not getting any errors or warnings), the DB remains empty.

I have been staring at this for hours, all ideas are welcome!

1 Answers

0
Maciej Kowalski On

There may be a transaction already running when the @Async is invoked and thus the asynchronous method picks the same transactional context.

The flip side is that before the async method finishes the transaction may have been committed by the parent code.

In general, it is advisable to invoke async methods with a new / nested transaction:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void import() {

Thanks to that it will not be dependent on the parent transaction.

UPDATE

Also you are saving a List of entities. Try using:

addressRepository.saveAll(adresses);