批量导入和@Transactional

时间:2014-03-03 20:26:58

标签: java spring jpa spring-data-jpa

我正在开发一个导入模块,以便从excel文件批量加载。我正在使用spring来管理事务上下文和spring-data-jpa(如DAO),以读取我正在使用POI的excel文件。

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

}

我希望如果在读取期间发生异常或行的保存没有任何变为持久性,但是内部异常不得导致回滚外部事务。

我该如何处理这种情况? 我正确地面对这个问题吗? 你能给我一些关于这个的建议(我是春天的新手)吗?

由于

1 个答案:

答案 0 :(得分:0)

良好的开端是Transaction management

Spring framework reference documentation部分

您的示例代码中有一些内容需要改进:

声明式事务管理

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.

这通常意味着调用您的private方法不会像您期望的那样遵守事务划分。在内部调用其他服务方法默认情况下不起作用,因为它不通过代理。在您的情况下,Using @Transactional提供了其他有用的参考。

@Transactional上的readRowFromExcel似乎毫无用处,因为您可以保证在致电import之前创建新的交易。

异常处理

为了让AOP代理管理在事务性方法期间抛出的异常,您必须确保在方法边界之外抛出异常,以便代理可以看到它。对于您的示例,执行某些操作部分应确保抛出相应的异常。如果要对异常进行细粒度的管理,则应该定义另一种异常类型而不是Exception

结束

如果要读取excel文件并使用Spring数据将内容保存到商店,则应该有一个公共注释方法,其目的是读取项目并使用Spring数据存储它。这需要对您的API进行一些重构。如果excel表格相当大,您还应该考虑 Spring Batch 来处理它。

外部交易的目的是什么?您还应该考虑故障情况,例如无法读取(或写入存储)某个特定行。您是在半处理文件还是在某处标记此错误?