Frage

I'm developing an import module to load in a bulk way from an excel file. I'm using spring to manage the transactional context and spring-data-jpa like DAO, to read a excel file I'm using POI.

@Service
public class ImportService{

    @Autowired
    UserRepository userRepository;

    @Autowired 
    UserDetailRepository userDetailRepository;

    @Autowired
    AddressRepository addressRepository;


@Transactional(propagation = Propagation.REQUIRES_NEW)
    public Map<String,StringBuffer> import(byte[] bytesUploaded) {


        wb  = new XSSFWorkbook(new ByteArrayInputStream(bytesUploaded));


        XSSFSheet mySheet = (XSSFSheet) wb.getSheetAt((short)0); 

        for(Row row: mySheet){

            if(row.getRowNum() >= 2 ){

                readRowFromExcel(row);

            }
        }
}

@Transactional(propagation = Propagation.NESTED,rollbackFor=Exception.class)
    private void readRowFromExcel(Row row) {

        try{

            User user = readUserFromFile(row);
            UserDetail = readUserDetailFromFile(row,user);
            Address address = readAddressFromFile(row,user);

            //A few check to verify the corretly load of the entities

            userDetailRepository.save(userDetail);
            addressRepository.save(address);
            userRepository.save(user);

        }
        catch (Exception e){
                //Do something
        }
    }

}

I would want that if an exception occurred during read or the save of the row nothing become persistent, however an internal exception mustn't cause rollback the outer transaction.

How can I manage this kind of situation? Am I facing the problem correctly? Can you give me some suggestion about this (I'm new of spring)?

Thanks

War es hilfreich?

Lösung

A good start is the Transaction management section of the Spring framework reference documentation

There are a few things in your sample code that needs improvements:

Declarative transaction management

See section 11.5.1

The most important concepts to grasp with regard to the Spring Framework’s 
declarative transaction support are that this support is enabled via AOP 
proxies, and that the transactional advice is driven by metadata (currently 
XML- or annotation-based). The combination of AOP with transactional metadata 
yields an AOP proxy that uses a TransactionInterceptor in conjunction with 
an appropriate PlatformTransactionManager implementation to drive transactions
around method invocations.

What that means typically is that calling your private method will not honour the transaction demarcation as you expect. Calling other methods of your service internally won't work either by default as it does not go through the proxy. In your case, Using @Transactional provides additional useful references.

The @Transactional on readRowFromExcel seems useless as you have the guarantee that a fresh transaction will be created before calling import.

Exception handling

In order for the AOP proxy to manage an exception thrown during a transactional method, you have to actually make sure the exception is thrown outside the method boundary so that the proxy can see it. In the case of your example, the do something part should make sure to throw the appropriate exception. If you want fine-grained management of the exception, you should probably define another exception type than Exception.

Wrapping up

If you want to read your excel file and save the content to your store using Spring data, you should probably have a single public annotated method whose purpose is to read an item and store it using Spring data. This would need some refactoring of your API. If the excel sheet is fairly large, you should also consider Spring Batch to process it.

What would be the purpose of the outer transaction here? You should also consider failure scenario such as when one particular row cannot be read (or written to the store). Are you leaving the file half-processed or are you flagging this error somewhere?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top