【问题标题】:Bulk import and @Transactional批量导入和@Transactional
【发布时间】:2014-03-03 20:26:58
【问题描述】:

我正在开发一个导入模块以从 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
        }
    }

}

我希望如果在读取或保存行期间发生异常,则不会持久化,但是内部异常不能导致外部事务回滚。

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

谢谢

【问题讨论】:

标签: java spring jpa spring-data-jpa


【解决方案1】:

一个好的开始是Spring framework reference documentationTransaction 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.

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

readRowFromExcel 上的 @Transactional 似乎没用,因为您可以保证在调用 import 之前会创建一个新事务。

异常处理

为了让 AOP 代理管理 事务 方法期间抛出的异常,您必须真正确保在方法边界之外抛出异常,以便代理可以看到它。在您的示例中, do something 部分应确保抛出适当的异常。如果您想要对异常进行细粒度管理,您可能应该定义除Exception 之外的其他异常类型。

结束

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

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

【讨论】:

  • 外部事务应该在无法读取一行时服务(我想在任何行有错误时继续读取),在这种情况下,我在 excel 文件中标记错误,而正确处理的行会从文件中删除。程序完成后,用户可能会得到带有错误的文件。我该怎么办?
猜你喜欢
  • 2017-06-05
  • 1970-01-01
  • 2010-09-23
  • 2013-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-27
相关资源
最近更新 更多